Skip to content

Commit 643a16a

Browse files
bluesheep1337gregkh
authored andcommitted
misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os
In some bad situation, the gts may be freed gru_check_chiplet_assignment. The call chain can be gru_unload_context->gru_free_gru_context->gts_drop and kfree finally. However, the caller didn't know if the gts is freed or not and use it afterwards. This will trigger a Use after Free bug. Fix it by introducing a return value to see if it's in error path or not. Free the gts in caller if gru_check_chiplet_assignment check failed. Fixes: 55484c4 ("gru: allow users to specify gru chiplet 2") Signed-off-by: Zheng Wang <[email protected]> Acked-by: Dimitri Sivanich <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fd2c930 commit 643a16a

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

drivers/misc/sgi-gru/grufault.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ int gru_handle_user_call_os(unsigned long cb)
648648
if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB)
649649
return -EINVAL;
650650

651+
again:
651652
gts = gru_find_lock_gts(cb);
652653
if (!gts)
653654
return -EINVAL;
@@ -656,7 +657,11 @@ int gru_handle_user_call_os(unsigned long cb)
656657
if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
657658
goto exit;
658659

659-
gru_check_context_placement(gts);
660+
if (gru_check_context_placement(gts)) {
661+
gru_unlock_gts(gts);
662+
gru_unload_context(gts, 1);
663+
goto again;
664+
}
660665

661666
/*
662667
* CCH may contain stale data if ts_force_cch_reload is set.
@@ -874,7 +879,11 @@ int gru_set_context_option(unsigned long arg)
874879
} else {
875880
gts->ts_user_blade_id = req.val1;
876881
gts->ts_user_chiplet_id = req.val0;
877-
gru_check_context_placement(gts);
882+
if (gru_check_context_placement(gts)) {
883+
gru_unlock_gts(gts);
884+
gru_unload_context(gts, 1);
885+
return ret;
886+
}
878887
}
879888
break;
880889
case sco_gseg_owner:

drivers/misc/sgi-gru/grumain.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -716,25 +716,34 @@ static int gru_check_chiplet_assignment(struct gru_state *gru,
716716
* chiplet. Misassignment can occur if the process migrates to a different
717717
* blade or if the user changes the selected blade/chiplet.
718718
*/
719-
void gru_check_context_placement(struct gru_thread_state *gts)
719+
int gru_check_context_placement(struct gru_thread_state *gts)
720720
{
721721
struct gru_state *gru;
722+
int ret = 0;
722723

723724
/*
724725
* If the current task is the context owner, verify that the
725726
* context is correctly placed. This test is skipped for non-owner
726727
* references. Pthread apps use non-owner references to the CBRs.
727728
*/
728729
gru = gts->ts_gru;
730+
/*
731+
* If gru or gts->ts_tgid_owner isn't initialized properly, return
732+
* success to indicate that the caller does not need to unload the
733+
* gru context.The caller is responsible for their inspection and
734+
* reinitialization if needed.
735+
*/
729736
if (!gru || gts->ts_tgid_owner != current->tgid)
730-
return;
737+
return ret;
731738

732739
if (!gru_check_chiplet_assignment(gru, gts)) {
733740
STAT(check_context_unload);
734-
gru_unload_context(gts, 1);
741+
ret = -EINVAL;
735742
} else if (gru_retarget_intr(gts)) {
736743
STAT(check_context_retarget_intr);
737744
}
745+
746+
return ret;
738747
}
739748

740749

@@ -934,7 +943,12 @@ vm_fault_t gru_fault(struct vm_fault *vmf)
934943
mutex_lock(&gts->ts_ctxlock);
935944
preempt_disable();
936945

937-
gru_check_context_placement(gts);
946+
if (gru_check_context_placement(gts)) {
947+
preempt_enable();
948+
mutex_unlock(&gts->ts_ctxlock);
949+
gru_unload_context(gts, 1);
950+
return VM_FAULT_NOPAGE;
951+
}
938952

939953
if (!gts->ts_gru) {
940954
STAT(load_user_context);

drivers/misc/sgi-gru/grutables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ extern int gru_user_flush_tlb(unsigned long arg);
632632
extern int gru_user_unload_context(unsigned long arg);
633633
extern int gru_get_exception_detail(unsigned long arg);
634634
extern int gru_set_context_option(unsigned long address);
635-
extern void gru_check_context_placement(struct gru_thread_state *gts);
635+
extern int gru_check_context_placement(struct gru_thread_state *gts);
636636
extern int gru_cpu_fault_map_id(void);
637637
extern struct vm_area_struct *gru_find_vma(unsigned long vaddr);
638638
extern void gru_flush_all_tlb(struct gru_state *gru);

0 commit comments

Comments
 (0)