suidされた所有者rootのスクリプトがroot権限で動作されない件を対処する

ALL
スポンサーリンク

bash/shスクリプトは、suid&所有者rootでも、root権で実行されない

suidビットが設定されている実行可能ファイルは、そのファイルの所有者の権限で実行されます。所有者がrootなら、root権限で動作します。
ただし、bashやsh(とそのスクリプト)はroot権限で動作させることができません。これは、スクリプトがroot権で実行されると、セキュリティ上危険なためのようです。

問題の確認

例えば、次の内容のファイル test.sh を作成し、chmod +x test.sh します。

#!/bin/sh
id -u

これを実行すると、現在ファイルを実行しているユーザーIDが表示されます。この場合は1000です。

$ ./test.sh
1000

ここで、次のようにして所有者をroot、suidビットをセットします。

sudo chown root test.sh
sudo chmod +s test.sh

以下のようにセットされています。

$ ls -l test.sh
-rwsr-sr-x 1 root user01 16 11月  9 09:22 test.sh

ここで test.sh を実行します。
rootで実行されるなら結果は0と表示されますが、実際は元のユーザー権限のまま実行されて、結果は1000となります。

$ ./test.sh
1000

なんとかroot権でbash/shスクリプトを実行する

直接bash/shスクリプトを実行するのでは無く、bash/shスクリプトを実行するプログラムを用意します。そのプログラムをsuidし、所有者もrootにして実行すると、bash/shスクリプトをroot権で実行できます。

次のCプログラムを用意します。
ここでは setuid_exec.c とします。このプログラムは、カレントディレクトリの exec.sh をroot権で実行します。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>


int main(int argc, char **argv){


  char *pathbuf;
  size_t n;


  if (clearenv() != 0) {
    perror( strerror(errno) );
    return errno;
  }

  n = confstr( _CS_PATH , NULL , 0 );
  if( n == 0 ){
    perror( strerror(errno) );
    return errno;
  }

  if( ( pathbuf = malloc(n) ) == NULL ){
    perror( strerror(errno) );
    return errno;
  }

  if( confstr( _CS_PATH , pathbuf , n ) == 0 ){
    perror( strerror(errno) );
    return errno;
  }

  if( setenv( "PATH" , pathbuf , 1 ) == -1 ){
    perror( strerror(errno) );
    return errno;
  }


  if( setenv( "LANG" , "ja_JP.UTF-8" , 1 ) == -1 ){
    perror( strerror(errno) );
    return errno;


  setuid( 0 );
  system( "./exec.sh" );

}

コンパイルします。

gcc -o setuid_exec setuid_exec.c

作成された setuid_exec の所有者をrootにし、suidビットもセットします。書き込み権限もrootのみにします

sudo chown root setuid_exec
sudo chmod 4755 setuid_exec

次の内容のファイル exec.sh を作成します。

#!/bin/sh
id -u

exec.sh の書き込み権限をrootのみにします。必ず実施してください。
exec.shにはsuidビットのセットは不要です。所有者もrootである必要はありませんが、以下では書き込み権限をrootのみにする都合上、所有者をrootにしています。

sudo chown root exec.sh
sudo chmod 755 exec.sh

exec.shを実行します。今度はrootで実行されました。

$ ./exec.sh
0

なお、注意点です。

setuid_exec では、環境変数をクリアしたうえでPATHにデフォルトをセット・LANGをセットした後に、exec.shを実行しています。(環境変数をクリア・PATH/LANGのセットは呼び出しもとのシェルには影響しません)
意図しない環境変数をセットされてexec.shを実行されることを防ぐためです。

また、setuid_exec から呼び出している exec.sh は、必ず書き込み権限はrootのみにします。exec.shを一般ユーザーも編集できると、root権限で任意の内容のスクリプトを実行されることになってしまいます。
セキュリティのため、必ず、留意してください。

参考

scripting – Allow setuid on shell scripts – Unix & Linux Stack Exchange
ENV03-C. 外部プログラムを呼び出す際は環境を無害化する

コメント