11import cpp
2- import semmle.code.cpp.commons.unix.Constants
2+ import semmle.code.cpp.commons.unix.Constants as UnixConstants
3+
4+ /**
5+ * Gets the number corresponding to the contents of `input` in base-16.
6+ * Note: the first two characters of `input` must be `0x`. For example:
7+ * `parseHex("0x123abc") = 1194684`.
8+ */
9+ bindingset [ input]
10+ int parseHex ( string input ) {
11+ exists ( string lowerCaseInput | lowerCaseInput = input .toLowerCase ( ) |
12+ lowerCaseInput .regexpMatch ( "0x[0-9a-f]+" ) and
13+ result =
14+ strictsum ( int ix |
15+ ix in [ 2 .. input .length ( ) ]
16+ |
17+ 16 .pow ( input .length ( ) - ( ix + 1 ) ) * "0123456789abcdef" .indexOf ( lowerCaseInput .charAt ( ix ) )
18+ )
19+ )
20+ }
21+
22+ /**
23+ * Gets the value defined by the `O_CREAT` macro if the macro
24+ * exists and if every definition defines the same value.
25+ */
26+ int o_creat ( ) {
27+ result =
28+ unique( int v |
29+ exists ( Macro m | m .getName ( ) = "O_CREAT" |
30+ v = parseHex ( m .getBody ( ) ) or v = UnixConstants:: parseOctal ( m .getBody ( ) )
31+ )
32+ )
33+ }
34+
35+ /**
36+ * Gets the value defined by the `O_TMPFILE` macro if the macro
37+ * exists and if every definition defines the same value.
38+ */
39+ int o_tmpfile ( ) {
40+ result =
41+ unique( int v |
42+ exists ( Macro m | m .getName ( ) = "O_TMPFILE" |
43+ v = parseHex ( m .getBody ( ) ) or v = UnixConstants:: parseOctal ( m .getBody ( ) )
44+ )
45+ )
46+ }
347
448bindingset [ n, digit]
549private string octalDigit ( int n , int digit ) {
@@ -20,11 +64,17 @@ string octalFileMode(int mode) {
2064 else result = "[non-standard mode: decimal " + mode + "]"
2165}
2266
67+ /**
68+ * Holds if the bitmask `value` sets the bits in `flag`.
69+ */
70+ bindingset [ value, flag]
71+ predicate setsFlag ( int value , int flag ) { value .bitAnd ( flag ) = flag }
72+
2373/**
2474 * Holds if the bitmask `mask` sets any of the bit fields in `fields`.
2575 */
2676bindingset [ mask, fields]
27- predicate sets ( int mask , int fields ) { mask .bitAnd ( fields ) != 0 }
77+ predicate setsAnyBits ( int mask , int fields ) { mask .bitAnd ( fields ) != 0 }
2878
2979/**
3080 * Gets the value that `fc` sets the umask to, if `fc` is a call to
@@ -83,16 +133,24 @@ abstract class FileCreationExpr extends FunctionCall {
83133 abstract int getMode ( ) ;
84134}
85135
86- class OpenCreationExpr extends FileCreationExpr {
136+ abstract class FileCreationWithOptionalModeExpr extends FileCreationExpr {
137+ abstract predicate hasModeArgument ( ) ;
138+ }
139+
140+ class OpenCreationExpr extends FileCreationWithOptionalModeExpr {
87141 OpenCreationExpr ( ) {
88- this .getTarget ( ) .getName ( ) = [ "open" , "_open" , "_wopen" ] and
89- sets ( this .getArgument ( 1 ) .getValue ( ) .toInt ( ) , o_creat ( ) )
142+ this .getTarget ( ) .hasGlobalOrStdName ( [ "open" , "_open" , "_wopen" ] ) and
143+ exists ( int flag | flag = this .getArgument ( 1 ) .getValue ( ) .toInt ( ) |
144+ setsFlag ( flag , o_creat ( ) ) or setsFlag ( flag , o_tmpfile ( ) )
145+ )
90146 }
91147
92148 override Expr getPath ( ) { result = this .getArgument ( 0 ) }
93149
150+ override predicate hasModeArgument ( ) { exists ( this .getArgument ( 2 ) ) }
151+
94152 override int getMode ( ) {
95- if exists ( this .getArgument ( 2 ) )
153+ if this .hasModeArgument ( )
96154 then result = this .getArgument ( 2 ) .getValue ( ) .toInt ( )
97155 else
98156 // assume anything is permitted
@@ -108,20 +166,35 @@ class CreatCreationExpr extends FileCreationExpr {
108166 override int getMode ( ) { result = this .getArgument ( 1 ) .getValue ( ) .toInt ( ) }
109167}
110168
111- class OpenatCreationExpr extends FileCreationExpr {
169+ class OpenatCreationExpr extends FileCreationWithOptionalModeExpr {
112170 OpenatCreationExpr ( ) {
113- this .getTarget ( ) .getName ( ) = "openat" and
114- this .getNumberOfArguments ( ) = 4
171+ this .getTarget ( ) .hasGlobalOrStdName ( "openat" ) and
172+ exists ( int flag | flag = this .getArgument ( 2 ) .getValue ( ) .toInt ( ) |
173+ setsFlag ( flag , o_creat ( ) ) or setsFlag ( flag , o_tmpfile ( ) )
174+ )
115175 }
116176
117177 override Expr getPath ( ) { result = this .getArgument ( 1 ) }
118178
119- override int getMode ( ) { result = this .getArgument ( 3 ) .getValue ( ) .toInt ( ) }
179+ override predicate hasModeArgument ( ) { exists ( this .getArgument ( 3 ) ) }
180+
181+ override int getMode ( ) {
182+ if this .hasModeArgument ( )
183+ then result = this .getArgument ( 3 ) .getValue ( ) .toInt ( )
184+ else
185+ // assume anything is permitted
186+ result = 0 .bitNot ( )
187+ }
120188}
121189
122190private int fopenMode ( ) {
123191 result =
124- s_irusr ( ) .bitOr ( s_irgrp ( ) ) .bitOr ( s_iroth ( ) ) .bitOr ( s_iwusr ( ) ) .bitOr ( s_iwgrp ( ) ) .bitOr ( s_iwoth ( ) )
192+ UnixConstants:: s_irusr ( )
193+ .bitOr ( UnixConstants:: s_irgrp ( ) )
194+ .bitOr ( UnixConstants:: s_iroth ( ) )
195+ .bitOr ( UnixConstants:: s_iwusr ( ) )
196+ .bitOr ( UnixConstants:: s_iwgrp ( ) )
197+ .bitOr ( UnixConstants:: s_iwoth ( ) )
125198}
126199
127200class FopenCreationExpr extends FileCreationExpr {
@@ -153,6 +226,6 @@ class FopensCreationExpr extends FileCreationExpr {
153226 // fopen_s has restrictive permissions unless you have "u" in the mode
154227 if this .getArgument ( 2 ) .getValue ( ) .charAt ( _) = "u"
155228 then result = fopenMode ( )
156- else result = s_irusr ( ) .bitOr ( s_iwusr ( ) )
229+ else result = UnixConstants :: s_irusr ( ) .bitOr ( UnixConstants :: s_iwusr ( ) )
157230 }
158231}
0 commit comments