最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

linux 可執(zhí)行文件與寫操作的同步問題(文件讀寫操作產(chǎn)生的鎖機(jī)制)

 更新時間:2013年10月22日 09:55:50   作者:  
在哪種系統(tǒng)下都會有文件操作產(chǎn)生的同步問題,今天說說linux下讀寫文件的鎖機(jī)制。
當(dāng)一個可執(zhí)行文件已經(jīng)為write而open時,此時的可執(zhí)行文件是不允許被執(zhí)行的。反過來,一個文件正在執(zhí)行時,它也是不允許同時被write模式而open的。這個約束很好理解,因為文件執(zhí)行和文件被寫應(yīng)該需要同步保護(hù),因此內(nèi)核會保證這種同步。那么內(nèi)核是如何實現(xiàn)該機(jī)制的呢?
Inode結(jié)點中包含一個數(shù)據(jù)項,叫做i_writecount,很明顯是用于記錄文件被寫的個數(shù)的,用于同步的,其類型也是atomic_t. 內(nèi)核中有兩個我們需要了解的函數(shù),與write操作有關(guān),分別是:

復(fù)制代碼 代碼如下:

int get_write_access(struct inode * inode)
{
    spin_lock(&inode->i_lock);
    if (atomic_read(&inode->i_writecount) < 0) {
                spin_unlock(&inode->i_lock);
        return -ETXTBSY;
    }
    atomic_inc(&inode->i_writecount);
        spin_unlock(&inode->i_lock);
    return 0;
}

int deny_write_access(struct file * file)
{
    struct inode *inode = file->f_path.dentry->d_inode;
        spin_lock(&inode->i_lock);
    if (atomic_read(&inode->i_writecount) > 0) {//如果文件被打開了,返回失敗
                spin_unlock(&inode->i_lock);
        return -ETXTBSY;
    }
        atomic_dec(&inode->i_writecount);
    spin_unlock(&inode->i_lock);
}

這兩個函數(shù)都很簡單,get_write_acess作用就和名稱一致,同樣deny_write_access也是。如果一個文件被執(zhí)行了,要保證它在執(zhí)行的過程中不能被寫,那么在開始執(zhí)行前應(yīng)該調(diào)用deny_write_access 來關(guān)閉寫的權(quán)限。那就來檢查execve系統(tǒng)調(diào)用有沒有這么做。
Sys_execve中調(diào)用do_execve,然后又調(diào)用函數(shù)open_exec,看一下open_exec的代碼:

復(fù)制代碼 代碼如下:

struct file *open_exec(const char *name)
{
    struct file *file;
    int err;
        file = do_filp_open(AT_FDCWD, name,
                O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
                MAY_EXEC | MAY_OPEN);

        if (IS_ERR(file))
        goto out;
        err = -EACCES;

    if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
        goto exit;

        if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
        goto exit;

        fsnotify_open(file->f_path.dentry);
    err = deny_write_access(file);//調(diào)用
       if (err)
        goto exit;

       out:
    return file;

       exit:
    fput(file);
    return ERR_PTR(err);
}

明顯看到了deny_write_access的調(diào)用,和預(yù)想的完全一致。在open的調(diào)用里,應(yīng)該有g(shù)et_write_access的調(diào)用。在open調(diào)用相關(guān)的__dentry_open函數(shù)中就包含了對該函數(shù)的調(diào)用。

復(fù)制代碼 代碼如下:

if (f->f_mode & FMODE_WRITE) {
    error = __get_file_write_access(inode, mnt);
    if (error)
            goto cleanup_file;
    if (!special_file(inode->i_mode))
      file_take_write(f);
}

其中__get_file_write_access(inode, mnt)封裝了get_write_access.
那么內(nèi)核又是如何保證一個正在被寫的文件是不允許被執(zhí)行的呢?這個同樣也很簡單,當(dāng)一個文件已經(jīng)為write而open時,它對應(yīng)的inode的i_writecount會變成1,因此在執(zhí)行execve時同樣會調(diào)用deny_write_access 中讀取到i_writecount>0之后就會返回失敗,因此execve也就會失敗返回。
這里是寫文件與i_writecount相關(guān)的場景:
寫打開一個文件時,在函數(shù)dentry_open中:
復(fù)制代碼 代碼如下:

if (f->f_mode & FMODE_WRITE) {
    error = get_write_access(inode);
    if (error)
    goto cleanup_file;
}

當(dāng)然在文件關(guān)閉時,會將i_writecount--;關(guān)閉時會執(zhí)行代碼:
復(fù)制代碼 代碼如下:

if (file->f_mode & FMODE_WRITE)
    put_write_access(inode);

put_write_access 代碼很簡單:
復(fù)制代碼 代碼如下:

static inline void put_write_access(struct inode * inode)
{
    atomic_dec(&inode->i_writecount);
}

于是乎自己寫了個簡單的代碼,一個空循環(huán),文件在執(zhí)行的時候,在bash中,echo 111 >>可執(zhí)行文件,結(jié)果預(yù)期之中,返回失敗,并提示信息 text file busy.
那么該機(jī)制是否同樣適用于映射機(jī)制呢,在執(zhí)行可執(zhí)行文件時,會mmap一些關(guān)聯(lián)的動態(tài)鏈接庫,這些動態(tài)鏈接庫是否被mmap之后就不允許被寫以及正在寫時不允許mmap呢?這個是需要考慮的,因為它關(guān)系到安全的問題。因為庫文件也是可執(zhí)行的代碼,被篡改同樣會引起安全問題。
Mmap在調(diào)用mmap_region的函數(shù)里,有一個相關(guān)的檢查:

復(fù)制代碼 代碼如下:

if (vm_flags & VM_DENYWRITE) {         
        error = deny_write_access(file);
    if (error)
        goto free_vma;
    correct_wcount = 1;
}

其中,mmap調(diào)用中的flags參數(shù)會被正確的賦值給vm_flags,對應(yīng)關(guān)系是MAP_DENYWRIRE被設(shè)置了,那么VM_DENYWRITE就對應(yīng)的也被設(shè)置。下面寫了個簡單的代碼,做一下測試:
復(fù)制代碼 代碼如下:

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
        int fd;
    void *src = NULL;
    fd = open("test.txt",O_RDONLY);
    if (fd != 0)
        {
        if ((src = mmap(0,5,PROT_READ|PROT_EXEC  ,MAP_PRIVATE|        MAP_DENYWRITE,fd,0))== MAP_FAILED)
                {
            printf("MMAP error\n");
            printf("%s\n",strerror(errno));
                }else{
            printf("%x\n",src);
        }
    }

        FILE * fd_t = fopen("test.txt","w");
    if( !fd_t)
    {
                printf("open for write error\n");
        printf("%s\n",strerror(errno));
        return 0;
    }

        if (fwrite("0000",sizeof(char),4,fd_t) != 4)
    {
        printf("fwrite error \n");
    }

     
        fclose(fd_t);
    close(fd);
    return 1;
}

最后的test.txt被寫成了”0000”,很奇怪,貌似MAP_DENTWRITE不起作用了。于是man mmap查看,發(fā)現(xiàn):

  MAP_DENYWRITE

  This  flag  is ignored.  (Long ago, it signaled that attempts to write to the underlying file should fail with ETXTBUSY. But this was a source of denial-of-service attacks.)

原來這個標(biāo)識在用戶層已經(jīng)不起作用了啊,而且還說明了原因,容易引起拒絕式服務(wù)攻擊。攻擊者惡意的將某些系統(tǒng)程序要寫的文件以MAP_DENYWRITE模式映射,會導(dǎo)致正常程序?qū)懳募?。不過VM_DENYWRITE在內(nèi)核里還是有使用的,在mmap中還是有對deny_write_access的調(diào)用, 但是對它的調(diào)用已經(jīng)不是由mmap中的flag參數(shù)的MAP_DENYWRITE驅(qū)動的了。
那與可執(zhí)行文件相關(guān)的動態(tài)鏈接庫文件就悲劇了,大家都知道動態(tài)鏈接庫使用的也是mmap,這也導(dǎo)致動態(tài)鏈接庫在運(yùn)行時可以被更改。其實我這就是為了確認(rèn)這點。這也導(dǎo)致我需要自己寫同步控制代碼了。我們可以使用inode中的i_security以及file結(jié)構(gòu)的f_secutiry變量來寫自己的同步邏輯,就是麻煩了不少,還要寫內(nèi)核模塊,哎,工作量又增加了啊。安全問題是個麻煩的問題...

相關(guān)文章

  • Linux系統(tǒng)中日志詳細(xì)介紹

    Linux系統(tǒng)中日志詳細(xì)介紹

    大家好,本篇文章主要講的是Linux系統(tǒng)中日志詳細(xì)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 在Linux上使用xargs命令的詳細(xì)教程

    在Linux上使用xargs命令的詳細(xì)教程

    這篇文章主要介紹了如何在Linux上使用xargs命令,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Linux常用查看硬件設(shè)備信息命令大全(值得收藏)

    Linux常用查看硬件設(shè)備信息命令大全(值得收藏)

    本文是小編收藏整理的關(guān)于linux查看硬件設(shè)備信息的命名,非常不錯,值得收藏,需要的朋友參考下吧
    2016-12-12
  • Linux如何設(shè)置服務(wù)自啟動

    Linux如何設(shè)置服務(wù)自啟動

    這篇文章主要介紹了Linux中設(shè)置服務(wù)自啟動的三種方式,ln -s 建立啟動軟連接
    2015-11-11
  • Linux下實現(xiàn)不活動用戶登錄超時后自動登出

    Linux下實現(xiàn)不活動用戶登錄超時后自動登出

    這篇文章主要介紹了Linux下實現(xiàn)不活動用戶登錄超時后自動登出 ,本文給大家?guī)砹怂姆N方式,每種方式都通過實例代碼文字給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2019-08-08
  • Windows 配置Apache以便在瀏覽器中運(yùn)行Python script的CGI模式

    Windows 配置Apache以便在瀏覽器中運(yùn)行Python script的CGI模式

    在前面的我的一篇文章中 “Windows XP下的Python 首次安裝配置和使用 ”談到當(dāng)想在Apache服務(wù)器下運(yùn)行Python script的時候,發(fā)現(xiàn)Apache的mod_python版本還不支持Python 2.6更別說3.0.1了,只有2.5之下的,折騰著卸載和安裝,最后還沒搞定,就先擱一邊了。
    2009-07-07
  • Centos rsync文件同步配置步驟分享

    Centos rsync文件同步配置步驟分享

    rsync是類unix系統(tǒng)下的數(shù)據(jù)鏡像備份工具,從軟件的命名上就可以看出來了——remote sync
    2012-09-09
  • 騰訊云上免費(fèi)部署HTTPS的方法步驟

    騰訊云上免費(fèi)部署HTTPS的方法步驟

    這篇文章主要介紹了騰訊云上免費(fèi)部署HTTPS的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • CentOS 6.5上的Tomcat啟動報錯問題解決方法

    CentOS 6.5上的Tomcat啟動報錯問題解決方法

    最近在搭建虛擬機(jī)環(huán)境,裝的是CentOSQL 6.5版本,然后裝的OpenJDK1.7,在Apache下載了一個純凈的Tomcat放到虛擬機(jī)上啟動報錯了
    2016-08-08
  • 在Linux中查看進(jìn)程占用的端口號

    在Linux中查看進(jìn)程占用的端口號

    今天小編就為大家分享一篇關(guān)于在Linux中查看進(jìn)程占用的端口號,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10

最新評論

齐河县| 达州市| 平原县| 亚东县| 黄大仙区| 乐昌市| 新安县| 马鞍山市| 东乌珠穆沁旗| 甘洛县| 汉川市| 江华| 玛多县| 竹山县| 历史| 长岛县| 涞源县| 永定县| 马边| 芦山县| 富川| 宿州市| 南平市| 丘北县| 固原市| 札达县| 和顺县| 莫力| 新源县| 昌宁县| 叶城县| 万源市| 德州市| 山阴县| 印江| 大渡口区| 湖北省| 天长市| SHOW| 牟定县| 巢湖市|