setuid とsetgid は、UNIXにおけるアクセス権を表すフラグの名称であり、ユーザーが実行ファイルを実行する際にその実行ファイルの所有者やグループの権限で実行できるようにする。それぞれ、setuserID とsetgroupID の略。一般ユーザーが高い特権レベルでしか実行できないタスクを一時的に実行できるようにする仕組みである。提供されるユーザー識別子やグループ識別子によって必ず特権レベルが高くなるわけではないが、少なくともそれら識別子は特定のものが指定されている。
setuid と setgid は一般ユーザーよりも高い特権レベルが必要とされるタスクの実行に必要である。例えば、そのユーザーのログインパスワードの変更などである。中には意外なタスクで特権レベルを上げる必要があることもある。例えば、ping コマンドはネットワークインタフェース上で制御パケットを送り、応答を待つ必要があり、特権が必要である(なお、現在ではsetuid以外の方法で権限を管理している場合もあるため、pingにsetuid属性が付与されているとは限らない[1][2])。
バイナリの実行ファイルに setuid 属性を付与したとき、一般ユーザーがそのファイルを実行すると、プロセス生成時にそのファイルの所有者(通常はroot)の特権を得ることができる。特に、root の権限がそのプロセスに与えられると、そのアプリケーションは一般ユーザーが通常ならできないタスクを実行できるようになる。このため setuid 属性を持つバイナリのプロセスは、一般的にセキュリティ対策として以下の制限下で実行される。
LD_LIBRARY_PATH やLD_PRELOAD 等を無効化することにより、setuid バイナリが依存している共有ライブラリやその動的リンカにおけるシンボル解決の挙動を実ユーザに変更させない。ptrace(2) やprocfs、一部のシグナル等、プロセスのデバッグに使用できる機能について、実ユーザからの利用を拒否する。一方、setuid バイナリを実行しているプロセスの特権として、seteuid(2) システムコールを発行することにより、プロセスの実効ユーザが root でない場合でも、これを setuid バイナリを起動した実ユーザまたは setuid バイナリの所有ユーザのいずれかへいつでも変更することができる。この機能のため、OS は setuid バイナリのプロセスを開始する際、setuid 先ユーザの情報をプロセスに保存しておく。[3]setegid(2)システムコールは、グループについて同じ機能を提供する。
これらの制限および特権は、setuid(2) システムコールを発行し、プロセスの実ユーザ、実効ユーザおよびプロセス開始時に保存したsetuid 先ユーザをまとめて再設定することにより解除される。グループについては、setgid(2) システムコールが同等機能となる。
セキュリティ上の危険を防ぐため、多くのオペレーティングシステムではシェルスクリプト形式の実行ファイルへの setuid 属性付与を無視するようになっている。また、perlにおける汚染モード(taint mode)[4]のように、スクリプト言語が独自にセキュリティ対策を実施している場合もある。
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/passwdalice:x:1007:1007::/home/alice:/bin/bashbob:x:1008:1008::/home/bob:/bin/bash[bob@foo]$catprintid.c#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>intmain(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());returnEXIT_SUCCESS;}[bob@foo]$gcc-Wallprintid.c-oprintid[bob@foo]$chmodug+sprintid[bob@foo]$sualicePassword:[alice@foo]$ls-l-rwsr-sr-x1bobbob69442007-11-0610:22printid[alice@foo]$./printidRealUID=1007EffectiveUID=1008RealGID=1007EffectiveGID=1008[alice@foo]$
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 では無視される[5]。FreeBSDでは設定が可能であり、setgid と同様に解釈される。すなわち、配下のファイルやサブディレクトリはそのディレクトリと同じ所有者となるよう設定される[6]。
setuid ビットはデニス・リッチーが発明した。リッチーを雇っていたAT&Tは1972年にその特許を申請し、1979年に特許 "Protection of data file contents"(4,135,240)が成立した。この特許は後にパブリックドメインとされた。[7]