dir属性に係るfile削除サンプル
Rev.3を表示中。最新版はこちら。
o-w:dirユーザ(aaa)でないユーザ(bbb)でのファイル作成が不可能。[aaa@north ~]$ mkdir dir [aaa@north ~]$ ls -l 合計 4 drwxrwxr-x 2 aaa aaa 4096 1月 24 12:15 dir [aaa@north ~]$ su -c "touch dir/file" bbb パスワード: touch: `dir/file' に touch できません: 許可がありません
o+w:dirユーザ(aaa)でないユーザ(bbb)でファイル作成が可能。
[aaa@north ~]$ chmod o+w dir [aaa@north ~]$ su -c "touch dir/file" bbb パスワード: [aaa@north ~]$ ls -l dir 合計 0 -rw-rw-r-- 1 bbb bbb 0 1月 23 14:11 fileo-t:fileユーザ(bbb)/dirユーザ(aaa)でないユーザ(ccc)での削除可能
[aaa@north ~]$ su -c "rm dir/file" ccc パスワード: rm: 書き込み保護されたファイル 通常の空ファイル `dir/file' を削除しますか?y [aaa@north ~]$ ls -l dir 合計 0o+t:ディレクトリユーザ(aaa)とファイルユーザ(bbb)でのみ削除可能
[aaa@north ~]$ chmod o+t dir [aaa@north ~]$ su -c "touch dir/file" bbb パスワード: [aaa@north ~]$ ls -l dir 合計 0 -rw-rw-r-- 1 bbb bbb 0 1月 23 14:12 file [aaa@north ~]$ su -c "rm dir/file" ccc パスワード: rm: 書き込み保護されたファイル 通常の空ファイル `dir/file' を削除しますか?y rm: `dir/file' を削除できません: 許可されていない操作です [aaa@north ~]$ su -c "rm dir/file" bbb パスワード: [aaa@north ~]$ ls -l dir 合計 0 [aaa@north ~]$ su -c "touch dir/file" bbb パスワード: [aaa@north ~]$ su -c "rm dir/file" aaa パスワード: rm: 書き込み保護されたファイル 通常の空ファイル `dir/file' を削除しますか?y [aaa@north ~]$ ls -l dir 合計 0
ファイル削除はunlinkシステムコール。
SYSCALL_DEFINE1(unlink, const char __user *, pathname)
{
return do_unlinkat(AT_FDCWD, pathname);
}
static long do_unlinkat(int dfd, const char __user *pathname)
{
int error;
struct filename *name;
struct dentry *dentry;
struct nameidata nd;
struct inode *inode = NULL;
name = user_path_parent(dfd, pathname, &nd);
if (IS_ERR(name))
return PTR_ERR(name);
error = -EISDIR;
if (nd.last_type != LAST_NORM)
goto exit1;
nd.flags &= ~LOOKUP_PARENT;
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit1;
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
dentry = lookup_hash(&nd);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
if (nd.last.name[nd.last.len])
goto slashes;
inode = dentry->d_inode;
if (!inode)
goto slashes;
ihold(inode);
error = security_path_unlink(&nd.path, dentry);
if (error)
goto exit2;
error = vfs_unlink(nd.path.dentry->d_inode, dentry);
exit2:
dput(dentry);
}
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
if (inode)
iput(inode); /* truncate the inode here */
mnt_drop_write(nd.path.mnt);
exit1:
path_put(&nd.path);
putname(name);
return error;
slashes:
error = !dentry->d_inode ? -ENOENT :
S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
goto exit2;
}
int vfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error = may_delete(dir, dentry, 0);
if (error)
return error;
if (!dir->i_op->unlink)
return -EPERM;
mutex_lock(&dentry->d_inode->i_mutex);
if (d_mountpoint(dentry))
error = -EBUSY;
else {
error = security_inode_unlink(dir, dentry);
if (!error) {
error = dir->i_op->unlink(dir, dentry);
if (!error)
dont_mount(dentry);
}
}
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
fsnotify_link_count(dentry->d_inode);
d_delete(dentry);
}
return error;
}
static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
{
int error;
if (!victim->d_inode)
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
return error;
if (IS_APPEND(dir))
return -EPERM;
if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
return -EPERM;
if (isdir) {
if (!S_ISDIR(victim->d_inode->i_mode))
return -ENOTDIR;
if (IS_ROOT(victim))
return -EBUSY;
} else if (S_ISDIR(victim->d_inode->i_mode))
return -EISDIR;
if (IS_DEADDIR(dir))
return -ENOENT;
if (victim->d_flags & DCACHE_NFSFS_RENAMED)
return -EBUSY;
return 0;
}
タスクデフォルトのcurrent->fsuidは、current->euid、current->euidのデフォルトはcurrent->uid
#define current_fsuid() (current_cred_xxx(fsuid)) ====> current->fsuid
static inline int check_sticky(struct inode *dir, struct inode *inode)
{
kuid_t fsuid = current_fsuid();
if (!(dir->i_mode & S_ISVTX))
return 0;
if (uid_eq(inode->i_uid, fsuid)) <-S_ISVTXなら、fileユーザなら削除OK
return 0;
if (uid_eq(dir->i_uid, fsuid) <-S_ISVTXなら、dirユーザなら削除OK
return 0;
return !inode_capable(inode, CAP_FOWNER);
}
S_APPEND/S_IMMUTABLE/S_SWAPFILEは、chattrでinode->i_flagsに設定されるファイル毎のinode属性で、ユーザに関わらず削除不可となる。#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE)




