blob: f57a1d9978825bd39a58a5ef5a273a8cea1050b5 [file] [log] [blame]
/// Recopying from the same user buffer frequently indicates a pattern of
/// reading a size header, allocating, and then re-reading an entire
/// structure. If the structure's size is not re-validated, this can lead
/// to structure or data size confusions.
///
// Confidence: Moderate
// Copyright: (C) 2013 Kees Cook, Chromium.
// Copyright: (C) 2016 Pengfei Wang.
// License: GPLv2.
// URL: http://coccinelle.lip6.fr/
// Comments:
// Options: --no-includes --include-headers
virtual report
virtual org
virtual context
@initialize:python@
@@
# -------------------------Post Matching Process--------------------------
def post_match_process(rule,p1,p2,src,ptr):
filename = p1[0].file
first = int(p1[0].line)
second = int(p2[0].line)
src_str = str(src)
ptr_str = str(ptr)
# Remove loop case, first and second fetch are not supposed to be
# in the same line.
if first == second:
return
# Remove reverse loop case, where first fetch behind second fetch
# but in last loop .
if first > second:
return
# Remove false matching of src ===> (int*)src , but leave
# function call like u64_to_uptr(ctl_sccb.sccb)
if src_str.find("(") == 0 or ptr_str.find("(") == 0:
return
coccilib.report.print_report(p2[0],
"potentially dangerous second copy_from_user() (rule %d: line %d vs line %d)" %
(rule, first, second))
//-----------------Pattern Matching Rules-----------------------------------
//------------------------------- case 1: normal case without src assignment
@ rule1 disable drop_cast exists @
expression addr,exp1,exp2,src,size1,size2,offset,e1,e2;
position p1,p2;
identifier func;
type T1,T2;
@@
func(...){
...
(
copy_from_user(exp1, (T1)src, size1)@p1
|
copy_from_user(exp1, src, size1)@p1
|
__copy_from_user(exp1, (T1)src, size1)@p1
|
__copy_from_user(exp1, src, size1)@p1
)
... when any
when != src = addr
when != src ++
when != src --
when != src += offset
when != src -= offset
when != src = src + offset
when != src = src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)src,size2)@p2
|
__copy_from_user(exp2, src,size2)@p2
|
copy_from_user(exp2,(T2)src,size2)@p2
|
copy_from_user(exp2, src,size2)@p2
)
...
}
@script:python depends on report@
p11 << rule1.p1;
p12 << rule1.p2;
s1 << rule1.src;
@@
if p11 and p12:
post_match_process(1, p11, p12, s1, s1)
//------------------------------ case 2: ptr = src at beginning, ptr first
@ rule2 disable drop_cast exists @
identifier func;
expression addr,exp1,exp2,src,ptr,size1,size2,offset,e1,e2;
position p0,p1,p2;
type T0,T1,T2;
@@
func(...){
...
(
ptr = (T0)src@p0 // potential assignment case
|
ptr = src@p0
)
...
(
copy_from_user(exp1, (T1)ptr,size1)@p1
|
copy_from_user(exp1, ptr,size1)@p1
|
__copy_from_user(exp1, (T1)ptr,size1)@p1
|
__copy_from_user(exp1, ptr,size1)@p1
)
...
when != src = addr
when != src ++
when != src --
when != src += offset
when != src -= offset
when != src = src + offset
when != src = src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)src,size2)@p2
|
__copy_from_user(exp2, src,size2)@p2
|
copy_from_user(exp2,(T2)src,size2)@p2
|
copy_from_user(exp2, src,size2)@p2
)
...
}
@script:python depends on report@
p21 << rule2.p1;
p22 << rule2.p2;
p2 << rule2.ptr;
s2 << rule2.src;
@@
if p21 and p22:
post_match_process(2, p21, p22, s2, p2)
//------------------------- case 3: ptr = src at beginning, src first
@ rule3 disable drop_cast exists @
identifier func;
expression addr,exp1,exp2,src,ptr,size1,size2,offset,e1,e2;
position p0,p1,p2;
type T0,T1,T2;
@@
func(...){
...
(
ptr = (T0)src@p0 // potential assignment case
|
ptr = src@p0
)
...
(
copy_from_user(exp1, (T1)src,size1)@p1
|
copy_from_user(exp1, src,size1)@p1
|
__copy_from_user(exp1, (T1)src,size1)@p1
|
__copy_from_user(exp1, src,size1)@p1
)
...
when != src = addr
when != src ++
when != src --
when != src += offset
when != src -= offset
when != src = src + offset
when != src = src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)ptr,size2)@p2
|
__copy_from_user(exp2, ptr,size2)@p2
|
copy_from_user(exp2,(T2)ptr,size2)@p2
|
copy_from_user(exp2, ptr,size2)@p2
)
...
}
@script:python depends on report@
p31 << rule3.p1;
p32 << rule3.p2;
p3 << rule3.ptr;
s3 << rule3.src;
@@
if p31 and p32:
post_match_process(3, p31, p32, s3, p3)
//----------------------------------- case 4: ptr = src at middle
@ rule4 disable drop_cast exists @
identifier func;
expression addr,exp1,exp2,src,ptr,size1,size2,offset,e1,e2;
position p0,p1,p2;
type T0,T1,T2;
@@
func(...){
...
(
copy_from_user(exp1, (T1)src,size1)@p1
|
copy_from_user(exp1, src,size1)@p1
|
__copy_from_user(exp1, (T1)src,size1)@p1
|
__copy_from_user(exp1, src,size1)@p1
)
...
when != src = addr
when != src ++
when != src --
when != src += offset
when != src -= offset
when != src = src + offset
when != src = src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
ptr = (T0)src@p0 // potential assignment case
|
ptr = src@p0
)
...
when != ptr = addr
when != ptr ++
when != ptr --
when != ptr += offset
when != ptr -= offset
when != ptr = ptr + offset
when != ptr = ptr - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)ptr,size2)@p2
|
__copy_from_user(exp2, ptr,size2)@p2
|
copy_from_user(exp2,(T2)ptr,size2)@p2
|
copy_from_user(exp2, ptr,size2)@p2
)
...
}
@script:python depends on report@
p41 << rule4.p1;
p42 << rule4.p2;
p4 << rule4.ptr;
s4 << rule4.src;
@@
if p41 and p42:
post_match_process(4, p41, p42, s4, p4)
//-------------------- case 5: first element, then ptr, copy from structure
@ rule5 disable drop_cast exists @
identifier func, f1;
expression addr,exp1,exp2,src,size1,size2,offset,e1,e2;
position p1,p2;
type T1,T2;
@@
func(...){
...
(
copy_from_user(exp1, (T1)src->f1,size1)@p1
|
copy_from_user(exp1, src->f1,size1)@p1
|
copy_from_user(exp1, &(src->f1),size1)@p1
|
__copy_from_user(exp1, (T1)src->f1,size1)@p1
|
__copy_from_user(exp1, src->f1,size1)@p1
|
__copy_from_user(exp1, &(src->f1),size1)@p1
)
...
when != src = addr
when != src ++
when != src --
when != src += offset
when != src -= offset
when != src = src + offset
when != src = src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)src,size2)@p2
|
__copy_from_user(exp2,src,size2)@p2
|
copy_from_user(exp2,(T2)src,size2)@p2
|
copy_from_user(exp2,src,size2)@p2
)
...
}
@script:python depends on report@
p51 << rule5.p1;
p52 << rule5.p2;
s5 << rule5.src;
e5 << rule5.f1;
@@
if p51 and p52:
post_match_process(5, p51, p52, s5, e5)
//---------------------- case 6: first element, then ptr, copy from pointer
@ rule6 disable drop_cast exists @
identifier func, f1;
expression addr,exp1,exp2,src,size1,size2,offset,e1,e2;
position p1,p2;
type T1,T2;
@@
func(...){
...
(
copy_from_user(exp1, (T1)src.f1, size1)@p1
|
copy_from_user(exp1, src.f1, size1)@p1
|
copy_from_user(exp1, &(src.f1), size1)@p1
|
__copy_from_user(exp1, (T1)src.f1, size1)@p1
|
__copy_from_user(exp1, src.f1, size1)@p1
|
__copy_from_user(exp1, &(src.f1), size1)@p1
)
...
when != &src = addr
when != &src ++
when != &src --
when != &src += offset
when != &src -= offset
when != &src = &src + offset
when != &src = &src - offset
when != if (size2 > e1 || ...) { ... return ...; }
when != if (size2 > e1 || ...) { ... size2 = e2 ... }
(
__copy_from_user(exp2,(T2)&src,size2)@p2
|
__copy_from_user(exp2,&src,size2)@p2
|
copy_from_user(exp2,(T2)&src,size2)@p2
|
copy_from_user(exp2,&src,size2)@p2
)
...
}
@script:python depends on report@
p61 << rule6.p1;
p62 << rule6.p2;
s6 << rule6.src;
e6 << rule6.f1;
@@
if p61 and p62:
post_match_process(6, p61, p62, s6, e6)