ratchet freak is right, it is a shallow copy. You can see the source to the dup function in dmd2/src/druntime/src/rt/lifetime.d. The function is called _adDupT.
It is a pretty short function where the main work is a call to memcpy(). Above the function, you can see a representation of an array: struct { size_t length; void* ptr; }
A jagged array would be an array of arrays, so the memory would look like [length0, ptr0, length1, ptr1, length2, ptr2....]
Since memcpy over those pointers doesn't follow them, that means slice.dup is a shallow copy.
This is generally true with anything that copies slices, it is always shallow copies unless you do something yourself. So struct A {char[] str; } A a, b; a = b; would also shallow copy, so assert(a.str is b.str).
If you want to do a deep copy, the simplest way is to just loop over it:
T[][] newArray;
foreach(item; oldArray)
newArray ~= item.dup;
(you can also preallocat newArray.length = oldArray.length and assign with indexes if you want to speed it up a bit)
A deep copy of a struct could be done with compile time reflection, though I prefer to write a clone method or something in there since it is a bit more clear.
I'm not aware of a phobos function with this premade.