258 lines
6.1 KiB
C
258 lines
6.1 KiB
C
// RUN: %clang_analyze_cc1 -analyzer-checker=core,security.SetgidSetuidOrder -verify %s
|
|
|
|
typedef int uid_t;
|
|
typedef int gid_t;
|
|
|
|
int setuid(uid_t);
|
|
int setgid(gid_t);
|
|
int seteuid(uid_t);
|
|
int setegid(gid_t);
|
|
int setreuid(uid_t, uid_t);
|
|
int setregid(gid_t, gid_t);
|
|
int setresuid(uid_t, uid_t, uid_t);
|
|
int setresgid(gid_t, gid_t, gid_t);
|
|
|
|
uid_t getuid();
|
|
gid_t getgid();
|
|
|
|
|
|
|
|
void correct_order() {
|
|
// A correct revocation sequence starts here.
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
// No warning for the following setgid statement.
|
|
// The previous setgid and setuid calls are a correct privilege revocation
|
|
// sequence. The checker does not care about the following statements (except
|
|
// if a wrong setuid-setgid sequence follows again).
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void incorrect_after_correct() {
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
// Incorrect sequence starts here.
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
}
|
|
|
|
void incorrect_order() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void warn_at_second_time() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
}
|
|
|
|
uid_t f_uid();
|
|
gid_t f_gid();
|
|
|
|
void setuid_other() {
|
|
if (setuid(f_uid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setgid_other() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(f_gid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setuid_other_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setuid(f_uid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setgid_with_getuid() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
// add a clang-tidy check for this case?
|
|
if (setgid(getuid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setuid_with_getgid() {
|
|
// add a clang-tidy check for this case?
|
|
if (setuid(getgid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
int f_setuid() {
|
|
return setuid(getuid());
|
|
}
|
|
|
|
int f_setgid() {
|
|
return setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
}
|
|
|
|
void function_calls() {
|
|
if (f_setuid() == -1)
|
|
return;
|
|
if (f_setgid() == -1)
|
|
return;
|
|
}
|
|
|
|
void seteuid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (seteuid(getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setegid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setegid(getgid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setreuid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setreuid(getuid(), getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setregid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setregid(getgid(), getgid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setresuid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setresuid(getuid(), getuid(), getuid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void setresgid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
if (setresgid(getgid(), getgid(), getgid()) == -1)
|
|
return;
|
|
if (setgid(getgid()) == -1)
|
|
return;
|
|
}
|
|
|
|
void getgid_getuid_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
(void)getgid();
|
|
(void)getuid();
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
}
|
|
|
|
void stored_getgid_getuid() {
|
|
// possible future improvement: detect this case
|
|
uid_t u = getuid();
|
|
gid_t g = getgid();
|
|
if (setuid(u) == -1)
|
|
return;
|
|
if (setgid(g) == -1) // no warning
|
|
return;
|
|
}
|
|
|
|
void f_extern();
|
|
|
|
void other_unknown_function_between() {
|
|
if (setuid(getuid()) == -1)
|
|
return;
|
|
f_extern();
|
|
if (setgid(getgid()) == -1) // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
}
|
|
|
|
void setuid_error_case() {
|
|
if (setuid(getuid()) == -1) {
|
|
// No warning if we know that the first setuid call has failed.
|
|
(void)setgid(getgid());
|
|
return;
|
|
}
|
|
(void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
}
|
|
|
|
void setuid_success_case() {
|
|
if (setuid(getuid()) == 0) {
|
|
if (setgid(getgid()) == 0) { // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
}
|
|
}
|
|
}
|
|
|
|
void incorrect_order_compare_zero() {
|
|
if (setuid(getuid()) != 0)
|
|
return;
|
|
(void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
}
|
|
|
|
void setuid_error_case_compare_zero() {
|
|
if (setuid(getuid()) != 0) {
|
|
// No warning if we know that the first setuid call has failed.
|
|
(void)setgid(getgid());
|
|
return;
|
|
}
|
|
}
|
|
|
|
void incorrect_order_compare_other() {
|
|
if (setuid(getuid()) == -2) {
|
|
// This is a case for improvement:
|
|
// The checker does not recognize that this is an invalid error check,
|
|
// but this is really another type of bug not related to this checker.
|
|
(void)setgid(getgid()); // warning should appear here
|
|
return;
|
|
}
|
|
if (setgid(getgid()) == -2) { // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
return;
|
|
}
|
|
}
|
|
|
|
const int FAIL = -1;
|
|
|
|
void incorrect_order_compare_var() {
|
|
if (setuid(getuid()) == FAIL)
|
|
return;
|
|
(void)setgid(getgid()); // expected-warning{{A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail}}
|
|
}
|