BigAdmin System Administration Portal
Solaris 10 最新セキュリティ技術 - 最小特権モデル
Print-friendly VersionPrint-friendly Version
Solaris Technical Article

Solaris 10 最新セキュリティ技術 - 最小特権モデル


Solaris 10 オペレーティングシステムは、新しいセキュリティ機能である "最小特権モデル" を提供します。 一般的な UNIX オペレーティングシステムでは、ほとんどのシステムプロセスが root 権限で実行されています。 これによりシステムプロセスを実行するために必要な権限が与えられる一方で、システムで保護されているその他の部分にも不要なアクセスを可能にしてしまいます。 このような問題に対処するために、Solaris 10 では、指定されたプロセスにスーパーユーザの権限のサブセットのみを付与する最小特権モデルを提供します。
今月は、Solaris 10 で新たに追加されたセキュリティ機能、最小特権モデルについて解説します。

はじめに

ほとんどの UNIX オペレーティング システムでは、システムプロセスの大部分がルート権限で実行され、プログラムから他のプロセスやメモリ、I/O デバイスなどに対する読み取りや変更が可能になっています。 これによりシステムプロセスを実行するために必要な権限が与えられる一方で、システムで保護されているその他の部分にも不要なアクセスを可能にしてしまいます。 多くのソフトウェアはこのような拡大された特権を悪用し、バッファオーバーフローやデータの破損などの欠陥を通じてスーパーユーザとしてマシンにアクセスします。 このような問題に対処するために、Solaris 10 オペレーティングシステムでは新しい最小特権モデルを採用しました。 このモデルでは、指定されたプロセスにスーパーユーザの権限のサブセットのみを付与し、すべての権限に対するフルアクセスを与えません。

最小特権モデルは、Sun が Trusted Solaris から得た経験を進化させ、そこで使用されていたセキュリティ モデルをさらに強化したものです。 Solaris 10 OS の最小特権モデルでは、一般ユーザがファイルシステムをマウントしたり、下位番号のポートにバインドするデーモンプロセスを起動したり、ファイルの所有権を変更したりする事が容易になります。 一方で、1024 以下のポートへのバインドや、ユーザのホームディレクトリに対する読み書き、イーサネットデバイスへのアクセスなど、限定されたアクセスが必要だったために以前は完全な root 権限で実行されていたプログラムからシステムを保護します。 setuid を使った root バイナリや完全な root 権限で実行されるデーモンは、最小特権モデルではほとんどの場合が不要になり、今後は、完全な root 権限を使用するという妥協手段がプログラムにおけるセキュリティ上の弱点となることはありません。 バッファオーバーフローなどのプログラミングエラーによる被害は、root 以外のユーザで実行されることで阻止され、保護されたシステムファイルへの読み書きや、マシンの停止などの重要な機能にアクセスされる心配はありせん。

Solaris 10 OS の最小権限モデルには、特権の基本セットに加えて、およそ 50 に細分化された特権が含まれています。 定義済みの特権は、contractcpcdtracefileipcnetprocsysなどのグループに分けられています。 特権の基本セットには、proc_forkproc_execproc_sessionproc_infofile_link_any など、従来のセキュリティモデルでは特権を持たなかったプロセスに対して付与されていたすべての権限が含まれます。

プロセスの特権セット

各プロセスは、そのカーネルクレデンシャル内に 4 つの特権セットを持っています。

  • 継承セット (I): exec に継承される特権。
  • 許可セット (P): プロセスの最大特権セット。
  • 実効セット (E): 現在有効な特権。P のサブセット。
  • 上限セット (L): プロセスおよびその子プロセスが取得する権限の上限。この特権 セット L に対する変更はすべて次の exec に影響します。
各プロセスには特権の認識状態 (Privilege Awareness State (PAS)) があり、Privilege Aware (PA) または Not-Privilege Aware (NPA) に設定することができます。 特権の認識とは、レガシーアプリケーションに従来の完全特権モデルとの完全な互換性を保持させるためのメカニズムです。 NPA であるレガシーアプリケーション は、EUID、RUID または SUID のいずれかが 0 (root) である場合に、特権セット L のすべての特権が許可されると考えられます。

プロセスが exec(2) を呼び出した場合、カーネルは Privilege Awareness を破棄しようとします。 特権を持たないプロセスでは、一般的に IPE は特権の基本セットと同じで、L は通常は定義済みの特権のフルセットです。 実装の背景にある理論の詳細については、blogs.sun.com にある Casper Dik's weblog(英語) および Process Rights Management Tutorial を参照してください。

プロセスは一度起動されると、特権の操作関数を使用して特権セットに特権の追加および削除を実行します。 特権は任意で削除できますが、許可セットの特権は実効セットおよび継承セットにのみ追加できます。 したがって継承セットは許可セットよりも大きくなります。 上限セットが大きくなることはありません。

ppriv(1) コマンド

プロセスの特権セットおよびその属性は、ppriv(1) プログラムを使用して表示および変更できます。 ppriv(1) プログラムの引数は以下のような形式になります。

    /usr/bin/ppriv -l [-v] [privilege-specification...]
    /usr/bin/ppriv [-v] [-S] [-D | -N] [-s spec] [pid | core]
    /usr/bin/ppriv -e [-D | -N] [-s spec] command [arg...]
前述のオプションは次のように定義されています:
  • -D: 指定されたプロセスまたはコマンドの特権のデバッグをオンにします。
  • -e: 引数の続きをコマンドラインとして解釈し、指定された特権セットと属性を使用してコマンドラインを実行します。
  • -l: 現在定義されているすべての特権を stdout にリストします。
  • -N: 指定されたプロセスまたはコマンドの特権のデバッグをオフにします。
  • -s spec: spec に従ってプロセスの特権セットを変更します。 各特権セットに正確に代入を行う場合、または追加および削除を何度も行う場合であれば、-s オプションを複数回使用して同じ特権セットを変更することもできます。 つまり、ある特権セットに対する代入および追加または削除は相互排他的な関係にあります。 spec[AEILP][+-=]privsetspec という形式で、スペースを含めることはできません。 詳細は、次のとおりです。
    • AEILP: 変更する特権セットを表す 1 つ以上の文字を指定します。 大文字小文字の区別はありません。 たとえば a または A のどちらも全ての特権セットを表します。
    • +-=: リストされた特権を、privsetspec で指定された特権セットに追加 (+)、削除 (-)、代入 (=) する修飾子を表します。
    • privsetspec: priv_str_to_set(3C) で説明されているように、カンマで区切られた特権セット (priv1priv2 など) を示します。
  • -S: 短い表示。特権セットをできるだけ短い出力形式でレポートします。 デフォルトでは簡易形式の出力です。 priv_str_to_set(3C) を参照してください。
  • -v: 冗長表示。特権名を使用して特権セットをレポートします。

プロセス特権の表示

プロセスが PA であるか否かによってどのように異なるのか、また特権はどのように変更されるのかについて検証するために、ppriv(1) コマンドを使用したプロセスをいくつか見てみましょう。 最初の例では、Not-Privilege Aware であるサードパーティのユーザプロセス screen について検証します。 flags には PRIV_AWARE が設定されておらず PIEは特権の基本セットとまったく同じ定義です。 特権セット L はすべて定義済みの特権セットです。

ppriv -v 1746

1746: screen -R

flags = 

E: file_link_any,proc_exec,proc_fork,proc_info,proc_session

I: file_link_any,proc_exec,proc_fork,proc_info,proc_session

P: file_link_any,proc_exec,proc_fork,proc_info,proc_session

L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,

dtrace_proc,dtrace_user,file_chown,file_chown_self,

file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,file_setid,

ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,

net_privaddr,net_rawaccess,proc_audit,proc_chroot,

proc_clock_highres,proc_exec,proc_fork,proc_info,

proc_lock_memory,proc_owner,proc_priocntl,

proc_session,proc_setid,proc_taskid,proc_zone,

sys_acct,sys_admin,sys_audit,sys_config,sys_devices,

sys_ipc_config,sys_linkdir,sys_mount,sys_net_config,

sys_nfs,sys_res_config,sys_resource,sys_suser_compat,

sys_time
2 番目の例では、inetd プロセスについて検証します。 このプロセスは Privilege Aware ではありませんが、EUID、RUID または SUIDが 0 で実行されるため、L と一致させるために P および E の特権セットが変更されています。

pcred 193

193: e/r/suid=0 e/r/sgid=0



ppriv -v 193

193: /usr/lib/inet/inetd start

flags = 

E: contract_event,contract_observer,cpc_cpu,dtrace_kernel,

dtrace_proc,dtrace_user,file_chown,file_chown_self,

file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,file_setid,

ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,

net_privaddr,net_rawaccess,proc_audit,proc_chroot,

proc_clock_highres,proc_exec,proc_fork,proc_info,

proc_lock_memory,proc_owner,proc_priocntl,proc_session,

proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,

sys_audit,sys_config,sys_devices,sys_ipc_config,

sys_linkdirsys_mount,sys_net_config,sys_nfs,

sys_res_config,sys_resource,sys_suser_compat,

sys_time

I: file_link_any,proc_exec,proc_fork,proc_info,proc_session

P: contract_event,contract_observer,cpc_cpu,dtrace_kernel,

dtrace_proc,dtrace_user,file_chown,file_chown_self,

file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,file_setid,

ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,

net_privaddr,net_rawaccess,proc_audit,proc_chroot,

proc_clock_highres,proc_exec,proc_fork,proc_info,

proc_lock_memory,proc_owner,proc_priocntl,proc_session,

proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,

sys_audit,sys_config,sys_devices,sys_ipc_config,

sys_linkdir,sys_mount,sys_net_config,sys_nfs,

sys_res_config,sys_resource,sys_suser_compat,sys_time

L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,

dtrace_proc,dtrace_user,file_chown,file_chown_self,

file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,file_setid,

ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,

net_privaddr,net_rawaccess,proc_audit,proc_chroot,

proc_clock_highres,proc_exec,proc_fork,proc_info,

proc_lock_memory,proc_owner,proc_priocntl,proc_session,

proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,

sys_audit,sys_config,sys_devices,sys_ipc_config,sys_linkdir,

sys_mount,sys_net_config,sys_nfs,sys_res_config,

sys_resource,sys_suser_compat,sys_time

3 番目の例では、fmd(1M) について見てみましょう。 このプロセスは Privilege Aware です。 flags の設定と EIPL の制限に注意してください。

ppriv -v 306

306: /usr/lib/fm/fmd/fmd

flags = PRIV_AWARE

E: file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,proc_exec,

proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,

sys_admin,sys_config,sys_devices,sys_res_config

I: file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,proc_exec,

proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,

sys_admin,sys_config,sys_devices,sys_res_config

P: file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,proc_exec,

proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,

sys_admin,sys_config,sys_devices,sys_res_config

L: file_dac_execute,file_dac_read,file_dac_search,

file_dac_write,file_link_any,file_owner,proc_exec,

proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,

sys_admin,sys_config,sys_devices,sys_res_config
最後の例では、lockd(1M) プロセスを見てみましょう。 このプロセスは PRIV_AWARE で、アクセスが非常に制限されています。

ppriv -v 161

161: /usr/lib/nfs/lockd

flags = PRIV_AWARE

E: sys_nfs

I: none

P: sys_nfs

L: none

プロセス特権のデバッグ

システム管理者は、一部のユーザにシステムタスクを実行できるように特権の選択を許可したいと考えることがよくあるでしょう。 ユーザが適切な特権を持っていない場合は、システムはエラーを出力してそのタスクは実行されません。 一般ユーザが使用できないように SUID のビットが /usr/sbin/traceroute ファイルから削除されました。 しかし、どのシステム管理者も root にならずに自分のアカウントから traceroute を使用できる必要があります。 特権を変更せずにホスト www に対して traceroute を試行すると、次のようなエラーが表示されます。

traceroute www
traceroute: icmp socket: Permission denied

様々なコマンドからどの特権が不足しているのかを見分けるには、シェルで ppriv(1) のデバッグ機能を使用します。

ppriv -D $$

traceroute www

traceroute[2885]: missing privilege "net_icmpaccess" (euid = 1001,

syscall = 230) for "devpolicy" needed at so_socket+0xa4

traceroute: icmp socket: Permission denied

これで UID 1001 を持つ人に PRIV_NET_ICMPACCESS の特権が不足していることがはっきりとわかります。 UID 1001 が traceroute を正常に実行できるように許可することができます。 問題を診断した後は、シェルでデバッグ機能を必ずオフにしてください。

ppriv -N $$j

シェル内の各コマンドをデバッグするかわりに、1 つのプロセスを 1 度にデバッグすることもできます。

ppriv -D -e dtrace -D test.d

特権と役割によるアクセス制御 (RBAC)

Solaris OS のバージョン 8 以降に存在する RBAC の機能は、特定の特権を Role(役割) またはユーザに割り当てるために使用します。 Solaris での RBAC の設定は、主に 4 つのファイルによって管理され、/etc/security/exec_attr/etc/security/prof_attr/etc/security/auth_attr/etc/user_attrexec_attr(4) に、プロファイルに関連付けられた実行属性を指定します。 設定には一般的に、ユーザ ID およびグループ ID、コマンド、デフォルトまたは制限される特権を指定します。 prof_attr(4) には一連の実行プロファイル名、説明、その他の属性を指定します。 auth_attr(4) には承認の定義と説明を指定します。 user_attr(4) には 割り当てられた承認、プロファイル、およびプロジェクトに加えてユーザおよび Role の定義を指定します。 RBAC の処理方法をさらに理解するには、前述のマニュア ル ページに加えて、rbac(5)policy.conf(4)chkauthattr(3SECDB) のマニュアル ページ、および Solaris 10 System Administrator Collection「役割、権利プロ ファイル、特権」の項目も参照してください。

あるユーザのグループに DTrace の使用を許可するには、システム管理者は DTrace 特権にアクセスできる Role を作成するか、ユーザに直接特権を付与します。 次の例では、"debug" という Role を作成し、適切な特権を付与しています。

roleadd -u 201 -d /export/home/debug -P "Process Management" debug
rolemod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user debug

次に usermod を使用して必要なユーザを debug という Role に追加します。

usermod -R debug username

debug という Role を持つユーザは、debug にアクセスするために su コマンドを使用することができ、適切なパスワードを提供し、必要な DTrace コマンドを実行することができます。

Role を追加し、ユーザに su コマンドを使用させて Role にアクセスさせるかわりに、システム管理者はユーザに直接特権を割り当てることもできます。 次のコマンド を成功させるには、ユーザはログアウトする必要があります。

usermod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user username

その他にも特権が必要な場合は、dtrace コマンドに ppriv を使用して再度実行し、必要な特権を特定してください。

RBAC は、特権の必要なポートにバインドする必要がある httpd などのデーモンをより安全に実行するために、最小特権モデルとともに使用することもできます。 このようなプログラムの多くは、実際には 1024 以下のポートを listen する以外には root としてのアクセスは必要ないため、プロセス net_privaddr を実行する Role または ユーザを許可すれば、今までのように EUID 0 を使用してプロセスを実行する必要はなくなります。

定義済みの特権セット

新しい最小特権モデルにおいて定義済みの特権は privileges(5) マニュアルページ に記載されていますが、ここではシステム管理者が使用する頻度の高いものをいくつか掲載します。

PRIV_CPC_CPU
プロセスに各 CPU ハードウェアのパフォーマンス カウンタへのアクセスを許可します。
PRIV_DTRACE_PROC
DTrace にプロセスレベルのトレースを許可します。 プロセスレベルトレースの Probe の設置を許可し、ユーザが権限を持つプロセス内で有効にします。
PRIV_DTRACE_USER
DTrace にユーザ レベルのトレースを許可します。 DTrace の syscall プロバイダやprofile プロバイダにユーザが権限をもつプロセスの検証を許可します。
PRIV_DTRACE_KERNEL
DTrace にカーネルレベルのトレースを許可します。
PRIV_FILE_CHOWN
プロセスに、ファイルの所有者のユーザ ID の変更を許可します。 プロセスがファイルのグループ ID を、プロセスが所有する有効なグループ ID 以外のグループ ID、またはプロセスの補助的なグループ ID に変更することを許可します。
PRIV_FILE_CHOWN_SELF
プロセスに、ファイルの配布を許可します。 この特権を持つプロセスは、{_POSIX_CHOWN_RESTRICTED} が有効でない場合と同様に実行されます。
PRIV_FILE_DAC_READ
パーミッションビットまたは ACL で読み取り権限を与えられていないファイルまたはディレクトリに対する読み取りをプロセスに許可します。
PRIV_FILE_DAC_SEARCH
パーミッションビットまたは ACL で検索の権限を与えられていないディレクトリの検索をプロセスに許可します。
PRIV_FILE_DAC_WRITE
パーミッションビットまたは ACL で書き込み権限を与えられていないファイルまたはディレクトリへの書き込みをプロセスに許可します。 すべての特権は、有効な UID 0 がない場合、UID 0 によって所有されているファイルへの書き込みが必要になります。
PRIV_FILE_OWNER
ファイルの所有者ではないプロセスに、ファイルのアクセスと変更時刻の修正を許可します。 また、ディレクトリの所有者ではないプロセスに、ディレクトリのアクセスと変更時刻の修正を許可します。 ファイルまたはディレクトリの所有者ではないプロセスに、親ディレクトリに「実行後にテキストイメージを保存する」(sticky) ビットセットを持つファイルまたはディレクトリの削除または名前変更を許可します。 フ ァイルの所有者ではないプロセスに、そのファイル上に namefs のマウントを許可します。 ファイルまたはディレクトリの所有者ではないプロセスに、そのファイルまたはディレクトリのパーミッションビットまたは ACL の変更を許可します。
PRIV_NET_ICMPACCESS
プロセスに、 ICMP パケットの送受信を許可します。
PRIV_NET_PRIVADDR
プロセスに、特権が必要なポート番号へのバインドを許可します。 "udp/tcp_extra_priv_ports" に示されているポートに加えて NFS が使用するために 予約されているポート以外に特権が必要なポート番号は 1 - 1023 (従来の UNIX で特権が必要なポート) です。
PRIV_PROC_SETID
プロセスに、任意の UID の設定を許可します。 UID 0 の場合はすべての特権が行使される必要があると仮定します。
PRIV_PROC_ZONE
プロセスに、他のゾーン内のプロセスに対するシグナルのトレースおよび送信を許可します。 zones(5) を参照してください。
PRIV_SYS_ADMIN
プロセスに、ノード名やドメイン名の設定、coreadm(1M) の指定および nscd(1M) の設定などのシステム管理者のタスクの実行を許可します。
PRIV_SYS_CONFIG
プロセスに、様々なシステム設定タスクの実行を許可します。 ファイル システムの ioctl の設定や、クォータ呼び出し、スナップショットの作成および削除、PCFS ブートセクタの操作などのファイルシステム固有の管理作業を許可します。
PRIV_SYS_DEVICES
プロセスに、デバイスの特別なファイルの作成を許可します。 許可されているアクセスを確認するために、drv_priv(9F) 関数を呼ぶカーネルモジュールの正常な呼び出しをプロセスに許可します。 プロセスに、実際のコンソールデバイスを直接オープンすることを許可します。 プロセスに、排他的にオープンされているデバイスのオープンを許可します。
PRIV_SYS_MOUNT
プロセスに、制限されているファイルシステム (namefs 以外のほとんどのファイルシステム) のマウントおよびマウント解除を許可します。 プロセスに、スワップ デバ イスの追加および削除を許可します。

特権セットの C 関数

特権の表示および変更には、様々な C 関数が使用されます。 Privilege Awareness を独自のコードに追加する方法についての詳細は、次のマニュアルページを参照してください。

  • getpflags(2), setpflags(2): プロセス フラグの取得または設定
  • getppriv(2), setppriv(2): 特権セットの取得または設定
  • priv_addset(3C) priv_allocset(3C), priv_copyset(3C), priv_delset(3C), priv_emptyset(3C), priv_fillset(3C), priv_freeset(3C), priv_intersect(3C), priv_inverse(3C), priv_isemptyset(3C), priv_isequalset(3C), priv_isfullset(3C), priv_ismember(3C), priv_issubset(3C), priv_union(3C): 特 権セットの操作関数
  • priv_set(3C), priv_ineffect(3C): 特権セットの変更および特権がセットされてい るかどうかの確認
  • priv_str_to_set(3C), priv_set_to_str(3C), priv_getbyname(3C), priv_getbynum(3C), priv_getsetbyname(3C), priv_getsetbynum(3C), priv_gettext(3C): 特権名の関数
  • priv_getbyname(9F): 特権名を数字へマップ
  • priv_policy(9F), priv_policy_only(9F), priv_policy_choice(9F): 権限の確認、 レポートおよび監査

リソース

この記事は、 The Least Privilege Model in the Solaris 10 OS (Amy Rich 著) を翻訳したものです。

BigAdmin
  
 
BigAdmin Upgrade Hub