#define _BSD_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <stdlib.h>
#define fatal_error() abort()
static void sanitize_privilege_drop_check(uid_t olduid, gid_t oldgid)
{
if (seteuid(olduid) != -1)
{
/* Privileges can be restored, handle error */
fatal_error();
}
if (setegid(oldgid) != -1)
{
/* Privileges can be restored, handle error */
fatal_error();
}
}
void badprivilegedroporder(void) {
uid_t
newuid = getuid(),
olduid = geteuid();
gid_t
newgid = getgid(),
oldgid = getegid();
if (setuid(newuid) == -1) {
/* handle error condition */
fatal_error();
}
if (setgid(newgid) == -1) {
/* handle error condition */
fatal_error();
}
if (olduid == 0) {
/* drop ancillary groups IDs only possible for root */
if (setgroups(1, &newgid) == -1) {
/* handle error condition */
fatal_error();
}
}
sanitize_privilege_drop_check(olduid, oldgid);
}В этом примере существует два отбрасывания привилегии, сделанные в неправильном порядке. setgid пытается пропустить привилегии группы. Однако setgid требует полномочий пользователя, которые были пропущены ранее с помощью setuid, чтобы выполнить эту функцию. После понижающихся привилегий группы эта функция пытается пропустить вспомогательные привилегии групп при помощи setgroups. Эта задача требует более высоких первичных привилегий группы, которые были пропущены с setgid. В конце этой функции возможно возвратить привилегии группы, потому что порядок понижающихся привилегий был неправильным.
Исправление — противоположный порядок отбрасывания привилегии
Одно возможное исправление должно пропустить самые низкие привилегии уровня сначала. В этом исправлении вспомогательные привилегии группы пропущены, затем пропущены первичные привилегии группы, и наконец полномочия пользователя пропущены.
#define _BSD_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <stdlib.h>
#define fatal_error() abort()
static void sanitize_privilege_drop_check(uid_t olduid, gid_t oldgid)
{
if (seteuid(olduid) != -1)
{
/* Privileges can be restored, handle error */
fatal_error();
}
if (setegid(oldgid) != -1)
{
/* Privileges can be restored, handle error */
fatal_error();
}
}
void badprivilegedroporder(void) {
uid_t
newuid = getuid(),
olduid = geteuid();
gid_t
newgid = getgid(),
oldgid = getegid();
if (olduid == 0) {
/* drop ancillary groups IDs only possible for root */
if (setgroups(1, &newgid) == -1) {
/* handle error condition */
fatal_error();
}
}
if (setgid(getgid()) == -1) {
/* handle error condition */
fatal_error();
}
if (setuid(getuid()) == -1) {
/* handle error condition */
fatal_error();
}
sanitize_privilege_drop_check(olduid, oldgid);
}