web-dev-qa-db-ja.com

UID名前空間で、マップされていないUIDにuidを設定できますか?

私がユーザーID1000であるとします。私はUID名前空間内でプログラムを実行し、名前空間内のUID0を名前空間外のUID1000にマッピングします。次に、プログラムは自身のUIDを50に変更しようとしますが、名前空間の外部に対応するUIDがありません。

プログラムは自身の(カーネル)UIDを正常に変更しますか?もしそうなら、そのUIDは名前空間の外部からのものであるように見えますか?それはまだ1000ですか、それとも他のものですか?

5
Tanner Swett

私は(ついに)FedoraRawhideでテストしました。私の最初の印象は正しいようです。名前空間内でseteuid(50)を実行しても、名前空間内のuid 50が名前空間外のuidに対応していない場合、seteuidの呼び出しは単に失敗します。

ここでは、「kernel uid」を使用して、カーネル(およびユーザー名前空間外のほとんどのプロセス)から見たプロセスのuidを参照し、「subjective uid」を使用して、それ自体(および名前空間内の他のプロセス)。

テスト1

まず、rootがseteuid(50)を呼び出すとどうなるか見てみましょう。 Pythonを開いて、そのpidが何であるかを確認します。

[Fedora@ip-0-0-0-0 ~]$ Sudo python                             
Python 2.7.6 (default, Feb  4 2014, 15:36:52)                         
[GCC 4.8.2 20140120 (Red Hat 4.8.2-14)] on linux2                     
Type "help", "copyright", "credits" or "license" for more information.
>>> import os                                                         
>>> os.getpid()                                                       
1081                                                                  

2番目のターミナルでは、Pythonのカーネルuidが実際には0(ルート)であることがわかります。

[Fedora@ip-0-0-0-0 ~]$ ls -ld /proc/1081
dr-xr-xr-x. 9 root root 0 Feb  7 03:27 /proc/1081

もちろん、主観的なuidも0です。

>>> os.geteuid()  
0                 

そこで、uidを50に変更します。

>>> os.seteuid(50)

2番目のターミナルでは、カーネルuidが実際に50に変更されていることがわかります。

[Fedora@ip-0-0-0-0 ~]$ ls -ld /proc/1081
dr-xr-xr-x. 9 50 root 0 Feb  7 03:27 /proc/1081

テスト2

では、「unshare」を使用して新しいユーザー名前空間を作成しましょう。

[Fedora@ip-0-0-0-0 ~]$ unshare --user python                   
Python 2.7.6 (default, Feb  4 2014, 15:36:52)                         
[GCC 4.8.2 20140120 (Red Hat 4.8.2-14)] on linux2                     
Type "help", "copyright", "credits" or "license" for more information.
>>> import os                                                         
>>> os.getpid()                                                       
1084                                                                  

2番目のターミナルでは、このプロセスのカーネルuidが1000(Fedora)であることがわかります。

[Fedora@ip-0-0-0-0 ~]$ ls -ld /proc/1084
dr-xr-xr-x. 9 Fedora fedora 0 Feb  7 03:30 /proc/1084

しかし、最初の端末では、その主観的なuidが65534(マップされていない)であることがわかります。

>>> os.geteuid()
65534           

したがって、2番目のターミナルでは、pythonマッピングを提供します:

[Fedora@ip-0-0-0-0 ~]$ echo '0 1000 1' > /proc/1084/uid_map

最初のターミナルでは、Pythonの主観的なuidが0になっていることがわかります。

>>> os.geteuid()                     
0                                    

Pythonのuidを50に設定しようとしましたが、主観的なuid 50にはカーネルuidへのマッピングがないため、これは「無効な引数」(おそらくEINVAL)で失敗します。

>>> os.seteuid(50)                   
Traceback (most recent call last):   
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument 

2番目のターミナルでは、プロセスのカーネルuidが変更されていないことがわかります。

[Fedora@ip-0-0-0-0 ~]$ ls -ld /proc/1084
dr-xr-xr-x. 9 Fedora fedora 0 Feb  7 03:30 /proc/1084

そして最初のターミナルでは、プロセスの主観的なuidも変更されていないことがわかります。

>>> os.geteuid()
0               

テスト3

さて、複数のuidを含むマッピングを定義するとどうなりますか? LWN.netの記事 " 操作中の名前空間、パート5:ユーザー名前空間 "によると、pythonafteruidのマッピング(pythonを実行する前にuidをマッピングせずにこれを試しましたが、seteuid操作で「操作は許可されていません」と表示されました。)最初に、2番目の新しいユーザー名前空間でシェルを実行します。

[Fedora@ip-0-0-0-0 ~]$ unshare --user  
id: cannot find name for user ID 65534        
id: cannot find name for group ID 65534       
id: cannot find name for user ID 65534        
[I have no name!@ip-10-239-133-144 ~]$ echo $$
1798                                          

次に、2番目のターミナルで、マッピングを定義するためにrootになる必要があります。

[root@ip-10-239-133-144 Fedora]# echo '0 1000 2' > /proc/1798/uid_map

whoamiコマンドによると、主観的なuidはrootになっているので、Pythonを開いて、主観的なuidを1に設定しましょう。

[I have no name!@ip-0-0-0-0 ~]$ whoami                         
root                                                                  
[I have no name!@ip-0-0-0-0 ~]$ python                         
Python 2.7.6 (default, Feb  4 2014, 15:36:52)                         
[GCC 4.8.2 20140120 (Red Hat 4.8.2-14)] on linux2                     
Type "help", "copyright", "credits" or "license" for more information.
>>> import os                                                         
>>> os.seteuid(1)                                                     
>>> os.getpid()                                                       
1837                                                                  

2番目のターミナルでは、予想どおり、カーネルuidが1001になっていることがわかります。

[root@ip-10-239-133-144 Fedora]# ls -ld /proc/1837
dr-xr-xr-x. 9 1001 Fedora 0 Feb  7 04:00 /proc/1837

もう一度テスト2?

テスト3では、seteuid()の呼び出しを成功させるために、Pythonを実行する前にマッピングを定義する必要がありました。テスト2では、これを行いませんでした。したがって、明らかな質問です。つまり、Pythonを実行する前にマッピングを定義した場合、seteuid()の呼び出しは機能しますか?答えはノーであることがわかります。最初のターミナル:

[Fedora@ip-0-0-0-0 ~]$ unshare --user  
id: cannot find name for user ID 65534        
id: cannot find name for group ID 65534       
id: cannot find name for user ID 65534        
[I have no name!@ip-0-0-0-0 ~]$ echo $$
1861                                          

2番目のターミナル:

[Fedora@ip-0-0-0-0 ~]$ echo '0 1000 1' > /proc/1861/uid_map

最初のターミナル:

[I have no name!@ip-0-0-0-0 ~]$ whoami                         
root                                                                  
[I have no name!@ip-0-0-0-0 ~]$ python                         
Python 2.7.6 (default, Feb  4 2014, 15:36:52)                         
[GCC 4.8.2 20140120 (Red Hat 4.8.2-14)] on linux2                     
Type "help", "copyright", "credits" or "license" for more information.
>>> import os                                                         
>>> os.geteuid()                                                      
0                                                                     
>>> os.seteuid(50)                                                    
Traceback (most recent call last):                                    
  File "<stdin>", line 1, in <module>                                 
OSError: [Errno 22] Invalid argument                                  

結論

ユーザー名前空間内でのseteuidの呼び出しを成功させるには、seteuidに渡されるuidに、ユーザー名前空間外のマッピングが必要です。それ以外の場合、呼び出しはEINVALで失敗します。

7
Tanner Swett

フォークした後、翻訳を定義する必要があります。

LWN.netのすばらしい記事からの抜粋:「プロセスのユーザーIDとグループIDを返すシステムコール(たとえば、getuid()getgid())は、常にユーザー内に表示される資格情報を返します。呼び出しプロセスが存在する名前空間。ユーザーIDに名前空間内のマッピングがない場合、ユーザーIDを返すシステムコールは、ファイル_/proc/sys/kernel/overflowuid_で定義された値を返します。これは、標準システムではデフォルト値65534です。最初、ユーザー名前空間にはユーザーIDマッピングがないため、名前空間内のすべてのユーザーIDはこの値にマップされます。同様に、新しいユーザー名前空間にはグループIDのマッピングがなく、マップされていないすべてのグループIDは_/proc/sys/kernel/overflowgid_(デフォルトはoverflowuid)と同じです。」

基本的に、子孫をclone(2)オフすると、子のPIDが取得され、_/proc/CHILDPID/uid-map_および_/proc/CHILDPID/gid-map_のテーブルに追加して、の定義を開始できるようになります。翻訳。

私が状況を理解しているように、新しい名前空間内で翻訳なしでseteuid(50)を実行すると、翻訳が定義されるまでeuidは65534のままであることがわかります。上記のように、一致する翻訳がない場合は、overflowuid/overflowgidが置き換えられます。

ほとんどの状況を見事に説明しているLWN.netの記事はここにあります: http://lwn.net/Articles/532593/

2
etherfish