web-dev-qa-db-ja.com

ルート権限の削除

私はrootとして起動するデーモンを持っています(そのため、低いポートにバインドできます)。初期化後、安全上の理由からroot権限を削除してもらいたいと思います。

誰かが私に既知の正しいこれを行うCのコードを指摘できますか?

マニュアルページを読んだり、さまざまなアプリケーションでのさまざまな実装を調べたりしましたが、それらはすべて異なり、その一部は非常に複雑です。これはセキュリティ関連のコードであり、他の人が犯しているのと同じ過ちを再発明したくありません。私が探しているのは、ベストプラクティスであり、既知の優れたポータブルライブラリ関数であり、正しく機能するという知識のもとで使用できます。そのようなものは存在しますか?

参考までに、私はrootとして開始しています。別のuidとgidで実行するように変更する必要があります。補足グループを正しくセットアップする必要があります。その後、root権限に戻す必要はありません。

54
David Given

あなたはこの記事を探しています:

POS36-C。特権を放棄するときに正しい失効順序を確認する

そのページのコンテンツを複製せずにそこにいくつかの情報を最適に配置する方法がわからない...

16
Ben

すべての特権(ユーザーとグループ)を削除するには、ユーザーの前にグループを削除する必要があります。 useridgroupidには、ドロップ先のユーザーとグループのIDが含まれ、有効なIDもrootであると想定すると、これは setuid () および setgid()

_if (getuid() == 0) {
    /* process is running as root, drop privileges */
    if (setgid(groupid) != 0)
        fatal("setgid: Unable to drop group privileges: %s", strerror(errno));
    if (setuid(userid) != 0)
        fatal("setuid: Unable to drop user privileges: %S", strerror(errno));
}
_

偏執狂の場合は、root権限を取り戻そうとして失敗する可能性があります。失敗しない場合は、救済を行います。

_ if (setuid(0) != -1)
     fatal("ERROR: Managed to regain root privileges?");
_

また、まだ偏執狂である場合は、 seteuid() および setegid() も必要になることがありますが、setuid()およびsetgid( )プロセスがrootによって所有されている場合、すべてのIDがすでに設定されています。

補足グループを設定するPOSIX関数がないため( getgroups() はあるが、setgroups()がないため)、補足グループリストは問題です。 BSDとLinuxの拡張機能 setgroups() を使用できます。

chdir("/") または他のディレクトリに移動して、プロセスがルート所有のディレクトリに残らないようにする必要もあります。

あなたの質問は一般的にUnixに関するものなので、これは非常に一般的なアプローチです。 Linuxでは、これが推奨されるアプローチではなくなったことに注意してください。現在のLinuxバージョンでは、実行可能ファイルに _CAP_NET_BIND_SERVICE_機能 を設定し、通常のユーザーとして実行する必要があります。 rootアクセスは必要ありません。

46
Juliano

これが私が最も得意なことでした。

#define _GNU_SOURCE  // for secure_getenv()


int drop_root_privileges(void) {  // returns 0 on success and -1 on failure
    gid_t gid;
    uid_t uid;

    // no need to "drop" the privileges that you don't have in the first place!
    if (getuid() != 0) {
        return 0;
    }

    // when your program is invoked with Sudo, getuid() will return 0 and you
    // won't be able to drop your privileges
    if ((uid = getuid()) == 0) {
        const char *Sudo_uid = secure_getenv("Sudo_UID");
        if (Sudo_uid == NULL) {
            printf("environment variable `Sudo_UID` not found\n");
            return -1;
        }
        errno = 0;
        uid = (uid_t) strtoll(Sudo_uid, NULL, 10);
        if (errno != 0) {
            perror("under-/over-flow in converting `Sudo_UID` to integer");
            return -1;
        }
    }

    // again, in case your program is invoked using Sudo
    if ((gid = getgid()) == 0) {
        const char *Sudo_gid = secure_getenv("Sudo_GID");
        if (Sudo_gid == NULL) {
            printf("environment variable `Sudo_GID` not found\n");
            return -1;
        }
        errno = 0;
        gid = (gid_t) strtoll(Sudo_gid, NULL, 10);
        if (errno != 0) {
            perror("under-/over-flow in converting `Sudo_GID` to integer");
            return -1;
        }
    }

    if (setgid(gid) != 0) {
        perror("setgid");
        return -1;
    }
    if (setuid(uid) != 0) {
        perror("setgid");
        return -1;    
    }

    // change your directory to somewhere else, just in case if you are in a
    // root-owned one (e.g. /root)
    if (chdir("/") != 0) {
        perror("chdir");
        return -1;
    }

    // check if we successfully dropped the root privileges
    if (setuid(0) == 0 || seteuid(0) == 0) {
        printf("could not drop root privileges!\n");
        return -1;
    }

    return 0;
}
2
Bora M. Alper