Skip to content

Commit 1a457a7

Browse files
committed
runtime/thread: fix unsoundness in native method calls
1 parent 7566fd1 commit 1a457a7

File tree

4 files changed

+65
-32
lines changed

4 files changed

+65
-32
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ vm_symbols = { path = "generators/vm_symbols" }
100100
native-macros = { path = "native/macros" }
101101
libc = "0.2"
102102
windows = "0.61.3"
103-
libffi = "4.1.1"
103+
libffi = "5.0.0"
104104

105105
byteorder = "1.5.0"
106106
byte-slice-cast = "1.2.2"

runtime/src/objects/method/mod.rs

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -660,19 +660,19 @@ impl Method {
660660
}
661661

662662
#[cfg(feature = "libffi")]
663-
pub struct PreparedCfi {
663+
pub struct PreparedCfi<'a> {
664664
pub cfi: libffi::middle::Cif,
665-
pub args: Vec<libffi::middle::Arg>,
665+
pub args: Vec<libffi::middle::Arg<'a>>,
666666
}
667667

668668
impl Method {
669669
#[cfg(feature = "libffi")]
670-
pub fn prepare_cfi(
670+
pub fn prepare_cfi<'a>(
671671
&'static self,
672-
env: *mut jni::sys::JNIEnv,
673-
class: jni::sys::jclass,
674-
locals: &crate::stack::local_stack::LocalStack,
675-
) -> PreparedCfi {
672+
env: &'a *mut jni::sys::JNIEnv,
673+
receiver: libffi::middle::Arg<'a>,
674+
locals: &mut crate::stack::local_stack::LocalStackIter<'a>,
675+
) -> PreparedCfi<'a> {
676676
trait IntoFfiType {
677677
fn into_ffi_type(&self) -> Type;
678678
}
@@ -694,6 +694,23 @@ impl Method {
694694
}
695695
}
696696

697+
trait OperandArgExt {
698+
fn as_arg(&self) -> Arg<'_>;
699+
}
700+
701+
impl OperandArgExt for Operand<Reference> {
702+
fn as_arg(&self) -> Arg<'_> {
703+
match self {
704+
Operand::Int(val) => Arg::new(val),
705+
Operand::Float(val) => Arg::new(val),
706+
Operand::Double(val) => Arg::new(val),
707+
Operand::Long(val) => Arg::new(val),
708+
Operand::Reference(val) => Arg::new(val),
709+
Operand::Empty => unreachable!(),
710+
}
711+
}
712+
}
713+
697714
use libffi::middle::{Arg, Type};
698715

699716
let num_args = self.descriptor.parameters.len() + if self.is_static() { 2 } else { 1 };
@@ -702,56 +719,50 @@ impl Method {
702719
let mut args = Vec::with_capacity(num_args);
703720

704721
// env
705-
args.push(Arg::new(&env));
722+
args.push(Arg::new(env));
723+
args_types.push(Type::pointer());
724+
725+
// jclass or jobject
726+
args.push(receiver);
706727
args_types.push(Type::pointer());
707-
if self.is_static() {
708-
// jclass
709-
args.push(Arg::new(&class));
710-
args_types.push(Type::pointer());
711-
}
712728

713-
for (arg_ty, arg) in self.descriptor.parameters.iter().zip(locals.iter()) {
729+
for (arg_ty, operand) in self.descriptor.parameters.iter().zip(locals) {
714730
match arg_ty {
731+
FieldType::Void => {
732+
args_types.push(Type::void());
733+
continue;
734+
},
735+
715736
FieldType::Byte => {
716-
args.push(Arg::new(&(arg.expect_int() as i8)));
717737
args_types.push(Type::i8());
718738
},
719739
FieldType::Character => {
720-
args.push(Arg::new(&(arg.expect_int() as u16)));
721740
args_types.push(Type::u16());
722741
},
723742
FieldType::Double => {
724-
args.push(Arg::new(&(arg.expect_double())));
725743
args_types.push(Type::f64());
726744
},
727745
FieldType::Float => {
728-
args.push(Arg::new(&(arg.expect_float())));
729746
args_types.push(Type::f32());
730747
},
731748
FieldType::Integer => {
732-
args.push(Arg::new(&(arg.expect_int())));
733749
args_types.push(Type::i32());
734750
},
735751
FieldType::Long => {
736-
args.push(Arg::new(&(arg.expect_long())));
737752
args_types.push(Type::i64());
738753
},
739754
FieldType::Short => {
740-
args.push(Arg::new(&(arg.expect_int() as i16)));
741755
args_types.push(Type::i16());
742756
},
743757
FieldType::Boolean => {
744-
args.push(Arg::new(&(arg.expect_int() != 0)));
745758
args_types.push(Type::u8());
746759
},
747760
FieldType::Object(_) | FieldType::Array(_) => {
748-
args.push(Arg::new(&(unsafe { arg.expect_reference().raw() })));
749761
args_types.push(Type::pointer());
750762
},
751-
FieldType::Void => {
752-
args_types.push(Type::void());
753-
},
754763
}
764+
765+
args.push(operand.as_arg());
755766
}
756767

757768
let ret_ty = self.descriptor.return_type.into_ffi_type();

runtime/src/stack/local_stack.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl LocalStack {
6868
}
6969

7070
impl<'a> IntoIterator for &'a LocalStack {
71-
type Item = Operand<Reference>;
71+
type Item = &'a Operand<Reference>;
7272
type IntoIter = LocalStackIter<'a>;
7373

7474
fn into_iter(self) -> Self::IntoIter {
@@ -84,8 +84,8 @@ pub struct LocalStackIter<'a> {
8484
remaining: usize,
8585
}
8686

87-
impl Iterator for LocalStackIter<'_> {
88-
type Item = Operand<Reference>;
87+
impl<'a> Iterator for LocalStackIter<'a> {
88+
type Item = &'a Operand<Reference>;
8989

9090
fn next(&mut self) -> Option<Self::Item> {
9191
match self.inner.next() {
@@ -98,7 +98,7 @@ impl Iterator for LocalStackIter<'_> {
9898
}
9999

100100
self.remaining -= 1;
101-
Some(operand.clone())
101+
Some(operand)
102102
},
103103
}
104104
}

runtime/src/thread/mod.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::thread::frame::native::NativeFrame;
2424
use crate::{classes, globals, java_call};
2525

2626
use std::cell::{Cell, SyncUnsafeCell, UnsafeCell};
27+
use std::mem::MaybeUninit;
2728
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
2829
use std::thread::JoinHandle;
2930

@@ -477,8 +478,29 @@ impl JavaThread {
477478
jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort,
478479
};
479480
use libffi::low::CodePtr;
481+
use libffi::middle::Arg;
480482

481-
let cfi = method.prepare_cfi(self.env().raw(), method.class().into_jni(), &locals);
483+
let env = self.env().raw();
484+
let target_class = method.class().into_jni();
485+
486+
let mut locals = locals.iter();
487+
488+
// To keep the receiver live
489+
let mut this = MaybeUninit::uninit();
490+
491+
let receiver;
492+
if method.is_static() {
493+
receiver = Arg::new(&target_class);
494+
} else {
495+
let this_ref = locals
496+
.next()
497+
.expect("should have a receiver")
498+
.expect_reference();
499+
this.write(unsafe { this_ref.raw() });
500+
receiver = Arg::new(&this);
501+
}
502+
503+
let cfi = method.prepare_cfi(&env, receiver, &mut locals);
482504
ret = unsafe {
483505
match method.descriptor.return_type {
484506
FieldType::Byte => Some(Operand::Int(

0 commit comments

Comments
 (0)