Setuid

setuid と setgid は、UNIXにおけるアクセス権を表すフラグの名称であり、ユーザーが実行ファイルを実行する際にその実行ファイルの所有者やグループの権限で実行できるようにする。それぞれ、set user ID と set group ID の略。一般ユーザーが高い特権レベルでしか実行できないタスクを一時的に実行できるようにする仕組みである。提供されるユーザー識別子やグループ識別子によって必ず特権レベルが高くなるわけではないが、少なくともそれら識別子は特定のものが指定されている。
setuid と setgid は一般ユーザーよりも高い特権レベルが必要とされるタスクの実行に必要である。例えば、そのユーザーのログインパスワードの変更などである。中には意外なタスクで特権レベルを上げる必要があることもある。例えば、ping コマンドはネットワークインタフェース上で制御パケットを送り、応答を待つ必要があり、特権が必要である。

実行ファイルでの setuid

バイナリの実行ファイルに setuid 属性を付与したとき、一般ユーザーがそのファイルを実行すると、プロセス生成時にそのファイルの所有者（通常はroot）の特権を得ることができる。root の権限がそのプロセスに与えられると、そのアプリケーションは一般ユーザーが通常ならできないタスクを実行できるようになる。それを起動したユーザーがそのプロセスを何とかして通常でない動きをさせようとしても、それは禁止されている。例えば、ptrace を使ったり、LD_LIBRARY_PATH をいじったり、シグナルを送ったりといったことである（端末からのシグナルだけは受け付けられる）。セキュリティ上の危険性が増すため、多くのオペレーティングシステムではシェルスクリプト形式の実行ファイルへの setuid 属性付与を無視するようになっている。
setuid 機能は非常に便利だが、注意深く設計でされていないプログラムの実行ファイルに setuid 属性を付与すると、セキュリティ上の危険性が生じる。悪意あるユーザーがそのような実行ファイルを利用して特権を得たり、一般ユーザーが気づかないうちにトロイの木馬を実行してしまうといった可能性がある。
setgid 属性はプロセスのグループベースの特権を変更する。
setuid 属性があるのは、UNIXにおいて一般ユーザーが chroot システムコールを実行できないためである。
setuid ビットと setgid ビットは通常、chmod コマンドで八進数形式の最上位桁を 4 または 2（両方なら 6）を設定することでセットされる。'chmod 6711' としたとき、setuid ビットと setgid ビットがセットされ(6)、所有者は読み取り/書き込み/実行が可能で(7)、グループとその他のユーザーは実行だけ可能となる(11)。なお、最上位桁の最下位ビットはスティッキービットである。
chmod には多くの場合、これらのビットをシンボルで指定するシンボリックモードもある。下記の実施例で使っている 'chmod g+s' はその例である。
実施例にあるC言語のプログラムは、プロセスの実ユーザー識別子と実グループ識別子および実効ユーザー識別子と実効グループ識別子を表示するだけのものである。実施例ではまず、このプログラムを 'bob' というユーザーでコンパイルし、'chmod' を使って setuid と setgid をセットしている。'su' コマンド自身も setuid 機能を使っているが、ここではユーザーを 'alice' に変更するために使われている。'chmod' コマンドの効果は 'ls -l' でチェックでき、最終的にデモプログラムが実行され、識別子が変更されていることが表示される。/etc/passwd ファイルの内容と比較していただきたい。
なお、'nosuid' オプション付きでマウントされたボリューム上では、このプログラムの実効ユーザー識別子の変更は無視される（変更されず、エラーも表示されない）。

実施例

[bob@foo]$ cat /etc/passwd
alice:x:1007:1007::/home/alice:/bin/bash
bob:x:1008:1008::/home/bob:/bin/bash

[bob@foo]$ cat printid.c

#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>

int main(void){
    printf("Real UID\t= %d\n", getuid());
    printf("Effective UID\t= %d\n", geteuid());
    printf("Real GID\t= %d\n", getgid());
    printf("Effective GID\t= %d\n", getegid());

    return EXIT_SUCCESS;}[bob@foo]$ gcc -Wall printid.c -o printid
[bob@foo]$ chmod ug+s printid
[bob@foo]$ su alice 
Password: 
[alice@foo]$ ls -l
-rwsr-sr-x 1 bob bob 6944 2007-11-06 10:22 printid
[alice@foo]$ ./printid 
Real UID        = 1007
Effective UID   = 1008
Real GID        = 1007
Effective GID   = 1008[alice@foo]$

ディレクトリでの setuid

setuid と setgid はディレクトリでは全く別の意味を持つ。
ディレクトリでsetgidパーミッションを設定すると（chmod g+s）、その後そのディレクトリ配下に作成されるファイルやサブディレクトリはそのグループを継承する（作成したユーザーの主グループは無視される。影響を受けるのはグループだけで、所有者は通常通りである）。新たに作成されるサブディレクトリは setgid ビットも継承する。
典型的な使用例は、グループ間で共有されるディレクトリ、特にCVSやSubversionのリポジトリに対して設定することである。バージョン管理システムのプロセスが適切なumask（一般的に002）でリポジトリにアクセスすることで、GIDを利用したアクセス制御が可能となる。
既存のファイルやサブディレクトリは元のままである点に注意が必要である。既存のサブディレクトリへの setgid ビットの設定は手で行う必要がある。そのコマンド行は以下のようになる。
find /path/to/directory -type d -print0 | xargs -0 chmod g+s
または
[root@foo]# find /path/to/directory -type d -exec chmod g+s {} \;
setuidパーミッションをディレクトリに設定しようとしても、UNIX や Linux では無視される。FreeBSDでは設定が可能であり、setgid と同様に解釈される。すなわち、配下のファイルやサブディレクトリはそのディレクトリと同じ所有者となるよう設定される。

歴史

setuid ビットはデニス・リッチーが発明した。リッチーを雇っていたAT&Tは1972年にその特許を申請し、1979年に特許 "Protection of data file contents"（4,135,240）が成立した。この特許は後にパブリックドメインとされた。