ファイル参照チェック
chdir/open等のファイル参照時、do_inode_permission()で、inodeのpermissionから、参照内容に応じたチェックが行われます。
inodeオペレーションコールバックの.permissionが定義されていなければ、generic_permission()がコールされます。sysfs/procfs等では.permissionは定義されてますが、ext等のファイルシステムでは、定義されていません。
inode->i_opflags |= IOP_FASTPERMは、二回目以降のdo_inode_permission()コール時、inodeキャッシュのpermissionコールバックがNULLかのチェックでなく、inode->i_opflagsをビット演算によるチェックでの効率化故かと思いますが、他の箇所でIOP_FASTPERMを使用されておらず、permission()その物の負荷を考慮すると、意味の無い効率化かと思います。
inode_userns(inode)は、inodeの属するnamespaceで、プロセスnamespaceに関係なく、作成されるinodeは、root_userプロセスのnamespaceに属する事になります。ns_capable()は、カレントプロセスが指定されるケーパビリティを有しているかチェックします。
ディレクトリの時、inode/ACLの参照条件に関係なく、ケーパビリティがCAP_DAC_OVERRIDEなら読書き(ls/rm/)OK。CAP_DAC_READ_SEARCHなら読込み(ls)OKです。
ファイルでは、CAP_DAC_OVERRIDEなら読書き可能。実行でU/G/OのどれかがOKなら実行可能となります。(userチェックでuserのEXEがセットされてなく、otherのEXEがセットされているなら、実行できるという事です。)
CAP_DAC_READ_SEARCHなら、読込みのみOKです。
rootは、これ等のケーパビリティは設定されており、inode->i_modeで読み書き不可としても、読み書きできるのは、ケーパビリティ所以です。
current->cred->fsuidがinode->i_uid(ファイルを作成したユーザID)なら、User(mode >>= 6)でチェックします。
それ以外、ACLのチェックをし、in_group_p()で、setgroupsシステムコールで設定されるcred->group_info->blocks[]のプロセスが属するグループにinode->i_gidを有しているなら、Group(mode >>= 3)でチェックします。
inodeオペレーションコールバックの.permissionが定義されていなければ、generic_permission()がコールされます。sysfs/procfs等では.permissionは定義されてますが、ext等のファイルシステムでは、定義されていません。
inode->i_opflags |= IOP_FASTPERMは、二回目以降のdo_inode_permission()コール時、inodeキャッシュのpermissionコールバックがNULLかのチェックでなく、inode->i_opflagsをビット演算によるチェックでの効率化故かと思いますが、他の箇所でIOP_FASTPERMを使用されておらず、permission()その物の負荷を考慮すると、意味の無い効率化かと思います。
static inline int do_inode_permission(struct inode *inode, int mask) { if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { if (likely(inode->i_op->permission)) return inode->i_op->permission(inode, mask); spin_lock(&inode->i_lock); inode->i_opflags |= IOP_FASTPERM; spin_unlock(&inode->i_lock); } return generic_permission(inode, mask); }acl_permission_check()でinode->i_modeおよびACLに掛かる参照チェックを行い、参照不可ならケーパビリティに掛かる参照チェックを行います。
inode_userns(inode)は、inodeの属するnamespaceで、プロセスnamespaceに関係なく、作成されるinodeは、root_userプロセスのnamespaceに属する事になります。ns_capable()は、カレントプロセスが指定されるケーパビリティを有しているかチェックします。
ディレクトリの時、inode/ACLの参照条件に関係なく、ケーパビリティがCAP_DAC_OVERRIDEなら読書き(ls/rm/)OK。CAP_DAC_READ_SEARCHなら読込み(ls)OKです。
ファイルでは、CAP_DAC_OVERRIDEなら読書き可能。実行でU/G/OのどれかがOKなら実行可能となります。(userチェックでuserのEXEがセットされてなく、otherのEXEがセットされているなら、実行できるという事です。)
CAP_DAC_READ_SEARCHなら、読込みのみOKです。
rootは、これ等のケーパビリティは設定されており、inode->i_modeで読み書き不可としても、読み書きできるのは、ケーパビリティ所以です。
int generic_permission(struct inode *inode, int mask) { int ret; ret = acl_permission_check(inode, mask); if (ret != -EACCES) return ret; if (S_ISDIR(inode->i_mode)) { if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) return 0; if (!(mask & MAY_WRITE)) if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) return 0; return -EACCES; } if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) return 0; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (mask == MAY_READ) if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) return 0; return -EACCES; }inode->i_modeは、上位9ビットから3ビット単位で、u/g/oです。プロセスのnamespaceは、新規にnamespaceを設定しないかぎり、初期プロセスのそれを継承します。プロセスnamespaceがinodeのネームスペース(初期プロセスのnamespace)と異なる時、Other(mode >>= 0)でチェックします。
current->cred->fsuidがinode->i_uid(ファイルを作成したユーザID)なら、User(mode >>= 6)でチェックします。
それ以外、ACLのチェックをし、in_group_p()で、setgroupsシステムコールで設定されるcred->group_info->blocks[]のプロセスが属するグループにinode->i_gidを有しているなら、Group(mode >>= 3)でチェックします。
#define MAY_EXEC 0x00000001 #define MAY_WRITE 0x00000002 #define MAY_READ 0x00000004 static int acl_permission_check(struct inode *inode, int mask) { unsigned int mode = inode->i_mode; if (current_user_ns() != inode_userns(inode)) goto other_perms; if (likely(current_fsuid() == inode->i_uid)) mode >>= 6; else { if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { int error = check_acl(inode, mask); if (error != -EAGAIN) return error; } if (in_group_p(inode->i_gid)) mode >>= 3; } other_perms: if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) return 0; return -EACCES; }
#define inode_userns(inode) (&init_user_ns) #define current_user_ns() (current_cred_xxx(user_ns)) #define current_cred_xxx(xxx) \ ({ \ current_cred()->xxx; \ }) #define current_cred() \ rcu_dereference_protected(current->cred, 1) struct user_namespace init_user_ns = { .kref = { .refcount = ATOMIC_INIT(3), }, .creator = &root_user, };