web-dev-qa-db-ja.com

プログラムでroot権限でファイルに書き込む最も安全な方法は何ですか?

巨大なアプリケーションは、ある特定の時点で、root権限を必要とするファイルへの少数の書き込みを実行する必要があります。これは実際にはファイルではなく、ファイルとしてLinuxに公開されるハードウェアインターフェイスです。

アプリケーション全体にroot権限を与えないようにするため、重要なタスクを実行するbashスクリプトを作成しました。たとえば、次のスクリプトは、ハードウェアインターフェイスのポート17を出力として有効にします。

echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction

しかし、suidが私のシステムのbashスクリプトに対して無効になっているので、これを達成するための最良の方法は何だろうと思います。

  1. 提示されたいくつかの回避策を使用してください ここ

  2. メインアプリケーションからSudoを使用してスクリプトを呼び出し、それに応じてsudoersリストを編集して、スクリプトを呼び出すときにパスワードを要求しないようにします。私はechoにSudo権限を与えるのが少し不快です。

  3. fprintfを使用してCプログラムを記述し、それをsuid rootに設定するだけです。文字列とファイル名をハードコードし、rootだけが編集できるようにします。または、テキストファイルから文字列を読み取り、同様に誰もファイルを編集できないことを確認します。

  4. 上記の解決策よりも安全で簡単な解決策はありませんか?

35
vsz

Sudoechoへのアクセス権を与える必要はありません。実際、それは無意味です。 Sudo echo foo > bar、リダイレクトはrootではなく元のユーザーとして行われます。

Sudoを使用して小さなスクリプトを呼び出し、NOPASSWD:アクセスが必要なユーザーによる、そのスクリプト(およびその他の同様のスクリプト)のみへのアクセス。

これは常にSudoを使用するための最良/安全な方法です。 root権限が必要な少数のコマンドを独自のスクリプトに分離し、信頼されていない、または部分的に信頼されているユーザーがそのスクリプトをrootとしてのみ実行できるようにします。

小さなSudo- ableスクリプトは、ユーザーからの引数(または入力)を取らない(つまり、呼び出す他のすべてのプログラムにハードコードされたオプションと引数が必要です)か、引数を非常に注意深く検証する必要があります/ inputは、ユーザーから受け入れる必要があります。

検証で偏執的である-除外する「既知の悪い」ものを探すのではなく、「既知の良い」ものだけを許可し、不一致やエラー、またはリモートで疑わしいものでさえ中止します。

検証は、スクリプトのできるだけ早い段階で実行する必要があります(できればそれが実行される前にanythingをrootとして実行することが望ましい)。


私は本当に最初にこの回答を書いたときにこれを言及しているはずですが、スクリプトがシェルスクリプトの場合は[〜#〜] must [〜#〜]適切に引用します- all変数。ユーザーが入力した入力を含む変数をanyの方法で引用する場合は特に注意してください。ただし、一部の変数が安全であると仮定しないでくださいQUOTE THEM ALL

これには、ユーザーによって制御される可能性のある環境変数が含まれます(例:"$PATH""$HOME""$USER"など。そして間違いなく"$QUERY_STRING"および"HTTP_USER_AGENT" etc(CGIスクリプト)。実際、すべてを引用してください。複数の引数を使用してコマンドラインを作成する必要がある場合は、配列を使用して引数リストを作成し、それを引用符で囲みます-"${myarray[@]}"

「すべてを引用する」と何度も言ったことがありますか。それを覚えて。やれ。

33
cas

Gpioファイルの所有者を確認します。

ls -l /sys/class/gpio/

ほとんどの場合、グループgpioが所有していることがわかります。

-rwxrwx--- 1 root     gpio     4096 Mar  8 10:50 export
...

その場合は、ユーザーをgpioグループに追加するだけで、Sudoなしでアクセスを許可できます。

Sudo usermod -aG gpio myusername

変更を有効にするには、ログアウトしてから再度ログインする必要があります。

16
jpa

このための1つの解決策(特にLinuxデスクトップで使用されますが、他の場合にも適用可能)は D-Bus を使用してrootとして実行されている小さなサービスをアクティブ化し、 polkit を使用します承認。これは基本的にpolkitが設計されたの目的でした。 紹介ドキュメント から:

polkitは、非特権プログラム(「CLIENTS」)にサービスを提供する特権プログラム(「MECHANISMS」)が使用することを目的とした承認APIを提供します。システムアーキテクチャと全体像については、polkitのマニュアルページを参照してください。

ヘルパープログラムを実行するのではなく、権限のない大きなプログラムがバスにリクエストを送信します。ヘルパーは、システムブート時に開始されるデーモンとして実行されているか、または systemdによって必要に応じてアクティブ化される のいずれかです。次に、ヘルパーはpolkitを使用して、リクエストが承認された場所から送信されていることを確認します。 (または、この場合、やりすぎのように感じられる場合は、他のハードコードされた認証/承認メカニズムを使用できます。)

私は D-Busを介した通信に関する良い基本的な記事 を見つけました、そして私はそれをテストしていませんが、 これはミックスにpolkitを追加する基本的な例のようです

このアプローチでは、何もsetuidとマークする必要はありません。

7
mattdm

これを行う1つの方法は、Cで書かれたsetuid-rootプログラムを作成して、必要なことだけを実行し、それ以上は実行しないようにすることです。あなたの場合、ユーザー入力をまったく見る必要はありません。

#include <unistd.h>
#include <string.h>
#include <stdio.h>  // for perror(3)
// #include ...  more stuff for open(2)

static void write_str_to_file(const char*fn, const char*str) {
    int fd = open(fn, O_WRONLY)
    if (-1 == fd) {
        perror("opening device file");  // make this a CPP macro instead of function so you can use string concat to get the filename into the error msg
        exit(1);
    }
    int err = write(fd, str, strlen(str));
    // ... error check
    err = close(fd);
    // ... error check
}

int main(int argc, char**argv) {
    write_string_to_file("/sys/class/gpio/export", "17");
    write_string_to_file("/sys/class/gpio/gpio17/direction", "out");
    return 0;
}

環境変数などを使用してこれを覆す方法はありません。これは、システムコールを2回行うだけだからです。

欠点:すべてのシステムコールの戻り値を確認する必要があります。

メリット:エラーチェックは非常に簡単です。エラーが発生した場合は、perrorを入力して救済すると、ゼロ以外のステータスで終了します。エラーがある場合は、straceで調査してください。ニースのエラーメッセージを表示するのに、このプログラム自体は必要ありません。

5
Peter Cordes

SudoのエコーではなくBless Teeは、ルート権限を制限する必要がある状況にアプローチするための一般的な方法の1つです。/dev/nullへのリダイレクトは、出力のリークを停止することです-Tシャツはあなたが望むことをします。

echo "17" | Sudo tee /sys/class/gpio/export > /dev/null
echo "out" | Sudo tee /sys/class/gpio/gpio17/direction > /dev/null
3
Miles Gillham

目的のタスクを実行するスクリプトを作成できます。次に、OpenSSHで使用されるキーを提供することによってのみログインできる新しいユーザーアカウントを作成します。

注:キーファイルがあれば、だれでもそのスクリプトを実行できます。そのため、OpenSSHキーファイルが、タスクの実行を禁止したい人に読まれないようにしてください。

OpenSSH構成(authorized_keysファイル内)で、キーを指定する前に、次の「例」のテキストで説明されているように、コマンド(スペースが後に続く)を指定します。

command="myscript" keydata optionalComment

この構成オプションは、そのOpenSSHキーを特定のコマンドの実行のみに制限できます。これで、Sudoが権限を付与しましたが、OpenSSH構成は、ユーザーが実行できることを制限/制限するために実際に使用されているソリューションの一部であるため、ユーザーは他のコマンドを実行していません。これも「Sudo」設定ファイルほど複雑ではないので、OpenBSDを使用する場合、またはOpenBSDの新しい「doas」(「do as」)がより一般的になり始める場合(使用するオペレーティングシステムの将来のバージョンで) 、Sudo構成の多くの複雑さに挑戦する必要はありません。

0
TOOGAM