float * could point to the first element of an array of floats, and ought to be reinterpret_castable to that array type. And the result of that cast could point to the first element of a float [][] and so should be reinterpret_castable to that type, and so on. You ought to be able to compose such casts and just directly do 
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray);
An argument of the type float ** is not the same and should not be used this way.
To avoid undefined behavior the pointer must originate from an actual multi-dimensional array, and if the float* is used directly you cannot access more than the first row of the multi-dimensional matrix.
void foo(float *f) {
    f[3] = 10.;
    float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f);
    arr[1][1] = 10.;
}
void main() {
    float a[2][2];
    foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined
    float b[4];
    foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined
}
Given float arr[2][2]; nothing guarantees that &arr[0][1] + 1 is the same as &arr[1][0], as far as I have been able to determine. So although you can use a single dimensional array as a multi-dimensional array by doing f[i*width + j] you cannot treat a multi-dimensional array like a single dimensional array.
It's better to use C++'s compile-time type-safety instead of just relying on not accidentally passing the wrong thing or performing the wrong reinterpret_cast. To get type-safety using raw-arrays you should use references to the raw array type you want:
void foo(float (&f)[2][2]) {}
void foo(float (&f)[3][3]) {}
If you want to pass arrays by value you can't use raw arrays and should instead use something like std::array:
void foo(std::array<std::array<float,2>,2> f) {}
void foo(std::array<std::array<float,3>,3> f) {}