xref: /llvm-project/clang/test/Analysis/setgid-setuid-order.c (revision 11b97da83141db857361ec9535dcd637ffcd0439)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,security.SetgidSetuidOrder -verify %s
2 
3 typedef int uid_t;
4 typedef int gid_t;
5 
6 int setuid(uid_t);
7 int setgid(gid_t);
8 int seteuid(uid_t);
9 int setegid(gid_t);
10 int setreuid(uid_t, uid_t);
11 int setregid(gid_t, gid_t);
12 int setresuid(uid_t, uid_t, uid_t);
13 int setresgid(gid_t, gid_t, gid_t);
14 
15 uid_t getuid();
16 gid_t getgid();
17 
18 
19 
correct_order()20 void correct_order() {
21   // A correct revocation sequence starts here.
22   if (setgid(getgid()) == -1)
23     return;
24   if (setuid(getuid()) == -1)
25     return;
26   // No warning for the following setgid statement.
27   // The previous setgid and setuid calls are a correct privilege revocation
28   // sequence. The checker does not care about the following statements (except
29   // if a wrong setuid-setgid sequence follows again).
30   if (setgid(getgid()) == -1)
31     return;
32 }
33 
incorrect_after_correct()34 void incorrect_after_correct() {
35   if (setgid(getgid()) == -1)
36     return;
37   if (setuid(getuid()) == -1)
38     return;
39   // Incorrect sequence starts here.
40   if (setuid(getuid()) == -1)
41     return;
42   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
43     return;
44 }
45 
incorrect_order()46 void incorrect_order() {
47   if (setuid(getuid()) == -1)
48     return;
49   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
50     return;
51   if (setgid(getgid()) == -1)
52     return;
53 }
54 
warn_at_second_time()55 void warn_at_second_time() {
56   if (setuid(getuid()) == -1)
57     return;
58   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
59     return;
60   if (setuid(getuid()) == -1)
61     return;
62   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
63     return;
64 }
65 
66 uid_t f_uid();
67 gid_t f_gid();
68 
setuid_other()69 void setuid_other() {
70   if (setuid(f_uid()) == -1)
71     return;
72   if (setgid(getgid()) == -1)
73     return;
74 }
75 
setgid_other()76 void setgid_other() {
77   if (setuid(getuid()) == -1)
78     return;
79   if (setgid(f_gid()) == -1)
80     return;
81   if (setgid(getgid()) == -1)
82     return;
83 }
84 
setuid_other_between()85 void setuid_other_between() {
86   if (setuid(getuid()) == -1)
87     return;
88   if (setuid(f_uid()) == -1)
89     return;
90   if (setgid(getgid()) == -1)
91     return;
92 }
93 
setgid_with_getuid()94 void setgid_with_getuid() {
95   if (setuid(getuid()) == -1)
96     return;
97   // add a clang-tidy check for this case?
98   if (setgid(getuid()) == -1)
99     return;
100 }
101 
setuid_with_getgid()102 void setuid_with_getgid() {
103   // add a clang-tidy check for this case?
104   if (setuid(getgid()) == -1)
105     return;
106   if (setgid(getgid()) == -1)
107     return;
108 }
109 
f_setuid()110 int f_setuid() {
111   return setuid(getuid());
112 }
113 
f_setgid()114 int f_setgid() {
115   return setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
116 }
117 
function_calls()118 void function_calls() {
119   if (f_setuid() == -1)
120     return;
121   if (f_setgid() == -1)
122     return;
123 }
124 
seteuid_between()125 void seteuid_between() {
126   if (setuid(getuid()) == -1)
127     return;
128   if (seteuid(getuid()) == -1)
129     return;
130   if (setgid(getgid()) == -1)
131     return;
132 }
133 
setegid_between()134 void setegid_between() {
135   if (setuid(getuid()) == -1)
136     return;
137   if (setegid(getgid()) == -1)
138     return;
139   if (setgid(getgid()) == -1)
140     return;
141 }
142 
setreuid_between()143 void setreuid_between() {
144   if (setuid(getuid()) == -1)
145     return;
146   if (setreuid(getuid(), getuid()) == -1)
147     return;
148   if (setgid(getgid()) == -1)
149     return;
150 }
151 
setregid_between()152 void setregid_between() {
153   if (setuid(getuid()) == -1)
154     return;
155   if (setregid(getgid(), getgid()) == -1)
156     return;
157   if (setgid(getgid()) == -1)
158     return;
159 }
160 
setresuid_between()161 void setresuid_between() {
162   if (setuid(getuid()) == -1)
163     return;
164   if (setresuid(getuid(), getuid(), getuid()) == -1)
165     return;
166   if (setgid(getgid()) == -1)
167     return;
168 }
169 
setresgid_between()170 void setresgid_between() {
171   if (setuid(getuid()) == -1)
172     return;
173   if (setresgid(getgid(), getgid(), getgid()) == -1)
174     return;
175   if (setgid(getgid()) == -1)
176     return;
177 }
178 
getgid_getuid_between()179 void getgid_getuid_between() {
180   if (setuid(getuid()) == -1)
181     return;
182   (void)getgid();
183   (void)getuid();
184   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
185     return;
186 }
187 
stored_getgid_getuid()188 void stored_getgid_getuid() {
189   // possible future improvement: detect this case
190   uid_t u = getuid();
191   gid_t g = getgid();
192   if (setuid(u) == -1)
193     return;
194   if (setgid(g) == -1) // no warning
195     return;
196 }
197 
198 void f_extern();
199 
other_unknown_function_between()200 void other_unknown_function_between() {
201   if (setuid(getuid()) == -1)
202     return;
203   f_extern();
204   if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
205     return;
206 }
207 
setuid_error_case()208 void setuid_error_case() {
209   if (setuid(getuid()) == -1) {
210     // No warning if we know that the first setuid call has failed.
211     (void)setgid(getgid());
212     return;
213   }
214   (void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
215 }
216 
setuid_success_case()217 void setuid_success_case() {
218   if (setuid(getuid()) == 0) {
219     if (setgid(getgid()) == 0) { // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
220     }
221   }
222 }
223 
incorrect_order_compare_zero()224 void incorrect_order_compare_zero() {
225   if (setuid(getuid()) != 0)
226     return;
227   (void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
228 }
229 
setuid_error_case_compare_zero()230 void setuid_error_case_compare_zero() {
231   if (setuid(getuid()) != 0) {
232     // No warning if we know that the first setuid call has failed.
233     (void)setgid(getgid());
234     return;
235   }
236 }
237 
incorrect_order_compare_other()238 void incorrect_order_compare_other() {
239   if (setuid(getuid()) == -2) {
240     // This is a case for improvement:
241     // The checker does not recognize that this is an invalid error check,
242     // but this is really another type of bug not related to this checker.
243     (void)setgid(getgid()); // warning should appear here
244     return;
245   }
246   if (setgid(getgid()) == -2) { // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
247     return;
248   }
249 }
250 
251 const int FAIL = -1;
252 
incorrect_order_compare_var()253 void incorrect_order_compare_var() {
254   if (setuid(getuid()) == FAIL)
255     return;
256   (void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
257 }
258