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
570
571static bool get_desc(struct desc_struct *out, unsigned short sel)
572{
573 struct desc_ptr gdt_desc = {0, 0};
574 unsigned long desc_base;
575
576#ifdef CONFIG_MODIFY_LDT_SYSCALL
577 if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) {
578 bool success = false;
579 struct ldt_struct *ldt;
580
581
582 sel >>= 3;
583
584 mutex_lock(¤t->active_mm->context.lock);
585 ldt = current->active_mm->context.ldt;
586 if (ldt && sel < ldt->nr_entries) {
587 *out = ldt->entries[sel];
588 success = true;
589 }
590
591 mutex_unlock(¤t->active_mm->context.lock);
592
593 return success;
594 }
595#endif
596 native_store_gdt(&gdt_desc);
597
598
599
600
601
602
603
604
605 desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK);
606
607 if (desc_base > gdt_desc.size)
608 return false;
609
610 *out = *(struct desc_struct *)(gdt_desc.address + desc_base);
611 return true;
612}
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)
632{
633 struct desc_struct desc;
634 short sel;
635
636 sel = get_segment_selector(regs, seg_reg_idx);
637 if (sel < 0)
638 return -1L;
639
640 if (v8086_mode(regs))
641
642
643
644
645 return (unsigned long)(sel << 4);
646
647 if (user_64bit_mode(regs)) {
648
649
650
651
652 unsigned long base;
653
654 if (seg_reg_idx == INAT_SEG_REG_FS)
655 rdmsrl(MSR_FS_BASE, base);
656 else if (seg_reg_idx == INAT_SEG_REG_GS)
657
658
659
660
661 rdmsrl(MSR_KERNEL_GS_BASE, base);
662 else
663 base = 0;
664 return base;
665 }
666
667
668 if (!sel)
669 return -1L;
670
671 if (!get_desc(&desc, sel))
672 return -1L;
673
674 return get_desc_base(&desc);
675}
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx)
695{
696 struct desc_struct desc;
697 unsigned long limit;
698 short sel;
699
700 sel = get_segment_selector(regs, seg_reg_idx);
701 if (sel < 0)
702 return 0;
703
704 if (user_64bit_mode(regs) || v8086_mode(regs))
705 return -1L;
706
707 if (!sel)
708 return 0;
709
710 if (!get_desc(&desc, sel))
711 return 0;
712
713
714
715
716
717
718
719 limit = get_desc_limit(&desc);
720 if (desc.g)
721 limit = (limit << 12) + 0xfff;
722
723 return limit;
724}
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742int insn_get_code_seg_params(struct pt_regs *regs)
743{
744 struct desc_struct desc;
745 short sel;
746
747 if (v8086_mode(regs))
748
749 return INSN_CODE_SEG_PARAMS(2, 2);
750
751 sel = get_segment_selector(regs, INAT_SEG_REG_CS);
752 if (sel < 0)
753 return sel;
754
755 if (!get_desc(&desc, sel))
756 return -EINVAL;
757
758
759
760
761
762
763 if (!(desc.type & BIT(3)))
764 return -EINVAL;
765
766 switch ((desc.l << 1) | desc.d) {
767 case 0:
768
769
770
771 return INSN_CODE_SEG_PARAMS(2, 2);
772 case 1:
773
774
775
776 return INSN_CODE_SEG_PARAMS(4, 4);
777 case 2:
778
779
780
781 return INSN_CODE_SEG_PARAMS(4, 8);
782 case 3:
783
784 default:
785 return -EINVAL;
786 }
787}
788
789
790
791
792
793
794
795
796
797
798
799
800
801int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs)
802{
803 return get_reg_offset(insn, regs, REG_TYPE_RM);
804}
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs,
828 int regoff, unsigned long *base,
829 unsigned long *limit)
830{
831 int seg_reg_idx;
832
833 if (!base)
834 return -EINVAL;
835
836 seg_reg_idx = resolve_seg_reg(insn, regs, regoff);
837 if (seg_reg_idx < 0)
838 return seg_reg_idx;
839
840 *base = insn_get_seg_base(regs, seg_reg_idx);
841 if (*base == -1L)
842 return -EINVAL;
843
844 if (!limit)
845 return 0;
846
847 *limit = get_seg_limit(regs, seg_reg_idx);
848 if (!(*limit))
849 return -EINVAL;
850
851 return 0;
852}
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs,
878 int *regoff, long *eff_addr)
879{
880 insn_get_modrm(insn);
881
882 if (!insn->modrm.nbytes)
883 return -EINVAL;
884
885 if (X86_MODRM_MOD(insn->modrm.value) != 3)
886 return -EINVAL;
887
888 *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
889 if (*regoff < 0)
890 return -EINVAL;
891
892
893 if (insn->addr_bytes == 2)
894 *eff_addr = regs_get_register(regs, *regoff) & 0xffff;
895 else if (insn->addr_bytes == 4)
896 *eff_addr = regs_get_register(regs, *regoff) & 0xffffffff;
897 else
898 *eff_addr = regs_get_register(regs, *regoff);
899
900 return 0;
901}
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs,
926 int *regoff, long *eff_addr)
927{
928 long tmp;
929
930 if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
931 return -EINVAL;
932
933 insn_get_modrm(insn);
934
935 if (!insn->modrm.nbytes)
936 return -EINVAL;
937
938 if (X86_MODRM_MOD(insn->modrm.value) > 2)
939 return -EINVAL;
940
941 *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
942
943
944
945
946
947
948 if (*regoff == -EDOM) {
949 if (user_64bit_mode(regs))
950 tmp = regs->ip + insn->length;
951 else
952 tmp = 0;
953 } else if (*regoff < 0) {
954 return -EINVAL;
955 } else {
956 tmp = regs_get_register(regs, *regoff);
957 }
958
959 if (insn->addr_bytes == 4) {
960 int addr32 = (int)(tmp & 0xffffffff) + insn->displacement.value;
961
962 *eff_addr = addr32 & 0xffffffff;
963 } else {
964 *eff_addr = tmp + insn->displacement.value;
965 }
966
967 return 0;
968}
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs,
993 int *regoff, short *eff_addr)
994{
995 int addr_offset1, addr_offset2, ret;
996 short addr1 = 0, addr2 = 0, displacement;
997
998 if (insn->addr_bytes != 2)
999 return -EINVAL;
1000
1001 insn_get_modrm(insn);
1002
1003 if (!insn->modrm.nbytes)
1004 return -EINVAL;
1005
1006 if (X86_MODRM_MOD(insn->modrm.value) > 2)
1007 return -EINVAL;
1008
1009 ret = get_reg_offset_16(insn, regs, &addr_offset1, &addr_offset2);
1010 if (ret < 0)
1011 return -EINVAL;
1012
1013
1014
1015
1016
1017
1018 if (addr_offset1 != -EDOM)
1019 addr1 = regs_get_register(regs, addr_offset1) & 0xffff;
1020
1021 if (addr_offset2 != -EDOM)
1022 addr2 = regs_get_register(regs, addr_offset2) & 0xffff;
1023
1024 displacement = insn->displacement.value & 0xffff;
1025 *eff_addr = addr1 + addr2 + displacement;
1026
1027
1028
1029
1030
1031
1032
1033 *regoff = addr_offset1;
1034
1035 return 0;
1036}
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060static int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs,
1061 int *base_offset, long *eff_addr)
1062{
1063 long base, indx;
1064 int indx_offset;
1065
1066 if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
1067 return -EINVAL;
1068
1069 insn_get_modrm(insn);
1070
1071 if (!insn->modrm.nbytes)
1072 return -EINVAL;
1073
1074 if (X86_MODRM_MOD(insn->modrm.value) > 2)
1075 return -EINVAL;
1076
1077 insn_get_sib(insn);
1078
1079 if (!insn->sib.nbytes)
1080 return -EINVAL;
1081
1082 *base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
1083 indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
1084
1085
1086
1087
1088
1089
1090 if (*base_offset == -EDOM)
1091 base = 0;
1092 else if (*base_offset < 0)
1093 return -EINVAL;
1094 else
1095 base = regs_get_register(regs, *base_offset);
1096
1097 if (indx_offset == -EDOM)
1098 indx = 0;
1099 else if (indx_offset < 0)
1100 return -EINVAL;
1101 else
1102 indx = regs_get_register(regs, indx_offset);
1103
1104 if (insn->addr_bytes == 4) {
1105 int addr32, base32, idx32;
1106
1107 base32 = base & 0xffffffff;
1108 idx32 = indx & 0xffffffff;
1109
1110 addr32 = base32 + idx32 * (1 << X86_SIB_SCALE(insn->sib.value));
1111 addr32 += insn->displacement.value;
1112
1113 *eff_addr = addr32 & 0xffffffff;
1114 } else {
1115 *eff_addr = base + indx * (1 << X86_SIB_SCALE(insn->sib.value));
1116 *eff_addr += insn->displacement.value;
1117 }
1118
1119 return 0;
1120}
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs)
1140{
1141 unsigned long linear_addr = -1L, seg_base, seg_limit;
1142 int ret, regoff;
1143 short eff_addr;
1144 long tmp;
1145
1146 insn_get_modrm(insn);
1147 insn_get_displacement(insn);
1148
1149 if (insn->addr_bytes != 2)
1150 goto out;
1151
1152 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1153 ret = get_eff_addr_reg(insn, regs, ®off, &tmp);
1154 if (ret)
1155 goto out;
1156
1157 eff_addr = tmp;
1158 } else {
1159 ret = get_eff_addr_modrm_16(insn, regs, ®off, &eff_addr);
1160 if (ret)
1161 goto out;
1162 }
1163
1164 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
1165 if (ret)
1166 goto out;
1167
1168
1169
1170
1171
1172
1173
1174 if ((unsigned long)(eff_addr & 0xffff) > seg_limit)
1175 goto out;
1176
1177 linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base;
1178
1179
1180 if (v8086_mode(regs))
1181 linear_addr &= 0xfffff;
1182
1183out:
1184 return (void __user *)linear_addr;
1185}
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs)
1204{
1205 unsigned long linear_addr = -1L, seg_base, seg_limit;
1206 int eff_addr, regoff;
1207 long tmp;
1208 int ret;
1209
1210 if (insn->addr_bytes != 4)
1211 goto out;
1212
1213 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1214 ret = get_eff_addr_reg(insn, regs, ®off, &tmp);
1215 if (ret)
1216 goto out;
1217
1218 eff_addr = tmp;
1219
1220 } else {
1221 if (insn->sib.nbytes) {
1222 ret = get_eff_addr_sib(insn, regs, ®off, &tmp);
1223 if (ret)
1224 goto out;
1225
1226 eff_addr = tmp;
1227 } else {
1228 ret = get_eff_addr_modrm(insn, regs, ®off, &tmp);
1229 if (ret)
1230 goto out;
1231
1232 eff_addr = tmp;
1233 }
1234 }
1235
1236 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
1237 if (ret)
1238 goto out;
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251 if (!user_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit))
1252 goto out;
1253
1254
1255
1256
1257
1258 if (v8086_mode(regs) && (eff_addr & ~0xffff))
1259 goto out;
1260
1261
1262
1263
1264
1265
1266 linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base;
1267
1268
1269 if (v8086_mode(regs))
1270 linear_addr &= 0xfffff;
1271
1272out:
1273 return (void __user *)linear_addr;
1274}
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291#ifndef CONFIG_X86_64
1292static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
1293{
1294 return (void __user *)-1L;
1295}
1296#else
1297static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
1298{
1299 unsigned long linear_addr = -1L, seg_base;
1300 int regoff, ret;
1301 long eff_addr;
1302
1303 if (insn->addr_bytes != 8)
1304 goto out;
1305
1306 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1307 ret = get_eff_addr_reg(insn, regs, ®off, &eff_addr);
1308 if (ret)
1309 goto out;
1310
1311 } else {
1312 if (insn->sib.nbytes) {
1313 ret = get_eff_addr_sib(insn, regs, ®off, &eff_addr);
1314 if (ret)
1315 goto out;
1316 } else {
1317 ret = get_eff_addr_modrm(insn, regs, ®off, &eff_addr);
1318 if (ret)
1319 goto out;
1320 }
1321
1322 }
1323
1324 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, NULL);
1325 if (ret)
1326 goto out;
1327
1328 linear_addr = (unsigned long)eff_addr + seg_base;
1329
1330out:
1331 return (void __user *)linear_addr;
1332}
1333#endif
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
1351{
1352 if (!insn || !regs)
1353 return (void __user *)-1L;
1354
1355 switch (insn->addr_bytes) {
1356 case 2:
1357 return get_addr_ref_16(insn, regs);
1358 case 4:
1359 return get_addr_ref_32(insn, regs);
1360 case 8:
1361 return get_addr_ref_64(insn, regs);
1362 default:
1363 return (void __user *)-1L;
1364 }
1365}
1366