2017-07-03 76 views
3

我正在使用與shmgetshmat共享內存用於教育目的。
我試圖讓一個內存塊只能由它的創建者進行修改,而所有其他進程只能讀取。
但讀者進程可以以某種方式寫入沒有任何錯誤。

這是我的共享內存的創建者代碼:共享內存忽略Linux中的只讀標誌c

#include <sys/shm.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <string.h> 

int main(){ 
    int shmid = shmget((key_t)56666, 1, IPC_CREAT | O_RDONLY); 
    if (shmid ==-1) { 
     perror("Err0:"); 
     exit(EXIT_FAILURE); 
    } 
    void* shmaddr = shmat(shmid, (void *)0,0); 
    if (shmaddr == (void *)-1) { 
     perror("Err:"); 
     exit(EXIT_FAILURE); 
    } 
    *(char*)shmaddr = 'a'; 
    putchar(*(char*)shmaddr); 
    while(1); 
    return 0; 
} 

這是我的讀者代碼:

#include <sys/shm.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <string.h> 
int main(){ 
    int shmid = shmget((key_t)56666, 4, O_RDONLY); 
    if (shmid ==-1) { 
     perror("Err0:"); 
     exit(EXIT_FAILURE); 
    } 
    void* shmaddr = shmat(shmid, (void *)0,0); 
    if (shmaddr == (void *)-1) { 
     perror("Err:"); 
     exit(EXIT_FAILURE); 
    } 
    *(char*)shmaddr = 'b'; 
    putchar(*(char*)shmaddr); 
    return 0; 
} 

正如你所看到的讀者可以編輯的內存,但即使我在讀取器中將內存打開爲只讀並且在共享內存的創建者中使用只讀標誌創建內存,也不會發生錯誤。

+1

'shmget'不理解'O_RDONLY'標誌,因爲它是'open',而不是'shmget'的標誌。事實上,在Linux上,'O_RDONLY'標誌被定義爲0. – Art

+0

@藝術我也嘗試了'0444'而不是'O_RDONLY',但是我得到了相同的結果。 – TheLogicGuy

+1

'SHM_RDONLY'會更好。 – Stargateur

回答

1

我還沒有看到任何O_RDONLYSHM_RDONLY記錄爲在linux或freebsd手冊頁中的shmat(2)系統調用的標誌。這個問題可能是誤用或誤解了它的工作原理。更多關於這個在最後,因爲在嘗試後,我看到SHM_RDONLY是你應該用來控制只讀附件的標誌,而不是O_RDONLY(這在這裏沒用)

可能你必須指定權限位創建shmget(2)系統調用以禁用其他用戶進程的訪問權限,以實現您想要的功能。有了權限,它可以工作,或者你會對使用共享內存的系統有嚴重的安全問題(例如postgresql數據庫使用sysvipc共享內存段)

據我所知,實現的最好方法是運行作者作爲某個用戶的共享內存段,以及允許以不同用戶讀取它的進程,調整權限位以允許它們讀取但不寫入共享內存段。就像將所有進程放在同一組ID中一樣,編寫器進程作爲創建共享內存段的用戶,而其他進程只具有讀取權限,而對其他用戶ID沒有權限,這對於任何應用程序都是足夠的。

shmget((key_t)56666, 1, IPC_CREAT | 0640); 

並且以其他不同的用戶在同一組ID中運行其他進程。

編輯

在FreeBSD機器測試代碼(對不起,沒有Linux可用,但IPC調用是SysV的AT &牛逼UNIX調用,所以一切都應該是兼容)之後的創建過程中出錯停在shmat(2)通話以下消息:

$ shm_creator 
Err:: Permission denied 

最有可能是因爲你沒有給共享內存創建權限,甚至給業主(我試着想像你是不是開發爲您的機器root,是你; ))

ipcs(1)顯示:

[email protected] ~$ ipcs -m 
Shared Memory: 
T   ID   KEY MODE  OWNER GROUP 
m  65537  56666 ----------- usr1  usr1  

,你看有沒有權限位共享內存段活躍,但它已創建。我已經修改了你的程序,而不是在while(1);循環中執行busywait,做一個非消耗的cpu,等待sleep(3600);,它會讓它睡一個小時。

shm_creator.c

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <string.h> 
#include <unistd.h> 

int main(){ 
    int shmid = shmget((key_t)56666, 1, IPC_CREAT | 0640); 
    if (shmid ==-1) { 
     perror("Err0:"); 
     exit(EXIT_FAILURE); 
    } 
    void* shmaddr = shmat(shmid, (void *)0,0); 
    if (shmaddr == (void *)-1) { 
     perror("Err:"); 
     exit(EXIT_FAILURE); 
    } 
    *(char*)shmaddr = 'a'; 
    putchar(*(char*)shmaddr); 
    puts(""); 
    sleep(3600); 
    return 0; 
} 

我跑爲用戶usr1

[email protected]:~/shm$ shm_creator & 
[2] 76950 
a 

然後切換到另一個用戶usr2,並運行:

$ su usr2 
Password: 
[[email protected] /home/usr1/shm]$ shm_client & 
[1] 76963 
[[email protected] /home/usr1/shm]$ Err:: Permission denied 

,當你標記它發生在shmat(2)系統調用中。但是,如果我運行它usr1我得到:

[email protected]:~/shm$ shm_client 
b 

如果shm_client.c源文件中使用SHM_RDONLY爲標誌,上運行(無論是作爲相同或不同的用戶),我得到如下:

[email protected]:~/shm$ shm_client 
Segmentation fault (generated `core') 

這是預期的行爲,因爲你試着寫不可寫內存(這是附着只讀存儲器)

EDIT 2

在網上瀏覽linux手冊頁之後,可以參考SHM_RDONLY以允許以只讀方式附加共享內存段。不提供對只寫共享內存段的支持,否則。由於在freebsd上沒有文檔記錄,這個選項在那裏也是可用的(常量包含在合適的包含文件中),還有一些其他不精確的地方可以在freebsd手冊中找到(如使用S_IROWN,S_IWOWN,S_IRGRP,S_IWGRP,S_IROTHS_IWOTH標誌來控制權限位,並在手冊頁的概要沒有列入#include <sys/stat.h>

CONCLUSSION

如果SHM_RDONLY是在你的系統中可用,那麼你可以使用它作爲一個非搶佔方式不允許對共享內存進行寫訪問,但是如果您希望內核強制執行,則必須切換到用戶權限位做法。