dir属性に係るfile削除サンプル


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 file
o-t:fileユーザ(bbb)/dirユーザ(aaa)でないユーザ(ccc)での削除可能
[aaa@north ~]$ su -c "rm dir/file" ccc
パスワード:
rm: 書き込み保護されたファイル 通常の空ファイル `dir/file' を削除しますか?y
[aaa@north ~]$ ls -l dir
合計 0
o+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))              <-!S_ISVTXなら削除OK
               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);  <-rootなら削除OK
}
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)

最終更新 2018/01/25 14:45:07 - north
(2018/01/25 13:49:32 作成)


検索

アクセス数
3689290
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。