4

root priv は、seteuid の後でも Python にドロップできません。バグ?

編集の要約: gid をドロップするのを忘れていました。ただし、受け入れられた回答が役立つ場合があります。

やあ。Linux の Python 3.2 で root 権限を削除できません。実際、seteuid(1000) の後でも、root 所有の 400 モード ファイルを読み取ることができます。euid は確実に 1000 に設定されています。

空の os.fork() 呼び出しの後に、特権アクセスが正しく拒否されていることがわかりました。(しかし、それは親だけです。子供はまだ違法に読むことができます。)それはPythonのバグですか、それともLinuxのバグですか?

以下のコードを試してください。一番下の 3 行のうちの 1 行をコメントアウトし、root として実行します。

事前に感謝します。

#!/usr/bin/python3

# Python seteuid pitfall example.
# Run this __as__ the root.

# Here, access to root-owned files /etc/sudoers and /etc/group- are tried.
# Simple access to them *succeeds* even after seteuid(1000) which should fail.

# Three functions, stillRoot(), forkCase() and workAround() are defined.
# The first two seem wrong. In the last one, access fails, as desired.


# ***Comment out*** one of three lines at the bottom before execution.

# If your python is < 3.2, comment out the entire def of forkCase()

import os

def stillRoot():
    """Open succeeds, but it should fail."""
    os.seteuid(1000)
    open('/etc/sudoers').close()

def forkCase():
    """Child can still open it. Wow."""
    # setresuid needs python 3.2
    os.setresuid(1000, 1000, 0)
    pid = os.fork()
    if pid == 0:
        # They're surely 1000, not 0!
        print('uid: ', os.getuid(), 'euid: ', os.geteuid())
        open('/etc/sudoers').close()
        print('open succeeded in child.')
        exit()
    else:
        print('child pid: ', pid)
        open('/etc/group-').close()
        print('parent succeeded to open.')

def workAround():
    """So, a dummy fork after seteuid is necessary?"""
    os.seteuid(1000)
    pid = os.fork()
    if pid == 0:
        exit(0)
    else:
        os.wait()

    open('/etc/group-').close()

## Run one of them.

# stillRoot()
# forkCase()
# workAround()
4

1 に答える 1

7

Unix システムでプロセスの資格情報を操作するのは注意が必要です。Real、Effective、Saved-Set ユーザー ID がどのように相互に関連しているかを完全に理解することを強くお勧めします。「特権の削除」を台無しにするのは非常に簡単です。

あなたの特定の観察については... あなたが見落としているかもしれない単純な原因があるかどうか疑問に思っています. あなたのコードは一貫性のないテストを実行しており、/etc/sudoersおよび/etc/group-ファイルに正確なファイル許可を指定することを怠っています。/etc/sudoersパーミッション mode=440、uid=root、gid=root (私のシステムのデフォルトのパーミッション) があり、/etc/group-mode=400 がある場合、記述どおりに動作することが期待できます。

プロセスの GID を変更していないため、/etc/sudoersグループで読み取り可能であれば、常に読み取り可能である理由が説明されます。fork()プロセス資格情報を変更しません。ただし、親と子で異なるファイルをチェックしているため、コード例ではそのように見える場合があります。/etc/group-グループの読み取り権限がない場合は/etc/sudoers、明らかな問題が説明されます。

やろうとしているのが「権限を削除する」だけの場合は、次のコードを使用します。

os.setgid( NEW_GID )
os.setuid( NEW_UID )

一般的に言えば、プロセスの存続期間中にルート権限のオンとオフを切り替える必要がある場合にのみ、有効なユーザー ID を操作する必要があります。root パーミッションでいくつかのセットアップ操作を実行する必要があるだけで、それらのセットアップ操作が完了した後にそれらを必要としなくなる場合は、上記のコードを使用して取り消し不能にそれらを削除してください。

Linux でプロセス資格情報を操作するための便利なデバッグ ユーティリティは、の出力を出力すること/proc/self/statusです。このファイルの Uid 行と Gid 行には、現在のプロセスが保持している実際の、有効な、保存されたセット、およびファイル ID が (この順序で) 表示されます。 )。Python API を使用して同じ情報を取得できますが、このファイルの内容を「真実のデータ」と見なして、Python のクロスプラットフォーム API による潜在的な複雑化を回避できます。

于 2011-06-02T13:45:12.833 に答える