一、实验目的
1. 熟悉安胜安全操作系统的运行环境
2. 熟悉隐蔽通道的工作原理
二、实验内容
1.完成发送和接收程序的编写、编译和执行
2.演示存在的隐蔽通道场景:
三、实验过程、结果
(1)测试准备
1. 启动到隐蔽通道处理前的安全核SecLinux
2. 创建两个用户user_h和user_l,user_h的安全范畴包含user_l的安全范畴,user_h的安全级高于user_l的安全级。此外,设置用户主目录安全级与用户安全级相同;将两个用户主目录自主访问控制权限放开,即均通过chmod命令将其权限设为0777,允许u,g,o可读、写和执行。
3. 检验SecLinux的安全性:
高级用户可以读低安全级文件,但是不能创建低安全级文件,也不能通过拷贝等方式向下传递信息。低级用户无法读高安全级文件。
(2)选用的隐蔽通道:进程描述符信道
信道名称:
进程标识符信道
信道类型:
持久变量型
中介变量:
last_pid
存在条件:
系统中所有的进程共享同一个进程标识符符列表。无论系统采用何种安全策略,高安全级进程与低安全级进程都要共享这个列表,并且可以通过建立子进程得知当前可用进程标识符信道的值。如果系统的进程标识符信道表是干净的,即没有其它进程消耗进程标识符信道表,高低进程就可以根据进程标识符信道增长的情况了解其它进程的工作情况。
发送方动作:
发送方读取机密文件,然后,根据该文件内容的当前字节的ASIIC码决定创建的子进程数目,待接收方读取该信息后,删除这些子进程。
接受方动作:
创建子进程,得到当前的进程标识符信道,然后与上次创建子进程得到的进程标识符信道对比,可以知道其它进程创建的子进程数目。解释所得到的信息。
噪音情况:
高噪音。系统中存在的任何其它进程都可能创建子进程,从而导致接收方错误解释所得到的信息。如果再安排在其它用户不工作的时刻(比如午夜12点)传递信息,就可能获得较大带宽。
带宽估计:
最大可以达到160比特/秒。
处理措施:
采用随机化进程标识符信道或者加入Idle进程,该进程随机创建子进程。
标记变量:
CC_PID
(3)同步机制
采用sleep(秒)/usleep(微秒)制造同步。
当一个进程sleep时,就将cpu的控制权交给其他进程,直到sleep时间已到,重新获得cpu的控制权。
这种同步技术容易实现,适于演示。
但是由于进程发送不同字符所用时间不同,而sleep时间一旦指定就是固定的,不能在程序运行期间更改,因此这种同步必然造成时间浪费。
(4)实验结果
如下图所示,左侧是发送端cc_sender,右侧是接收端cc_receiver,发送端从同目录的sender_text.txt文件获取发送数据,通过隐蔽通道发送到接收端,接收端接到数据后保存到同目录的receiver_text.txt文件中,发送端文件中存放的数据是abcdefg。
从下图可以看到receiver_text.txt的内容,可以看出,7个字符abcdefg都正确传输。
(5)发送端源代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void sendChar(char ch);
int main()
{
char ch;
FILE *fp;
int i;
if ((fp = fopen("./sender_text.txt", "r")) == NULL) //打开要发送的文件
{
printf("fopen error.\n");
exit(0);
}
while ((ch = fgetc(fp)) != EOF)
{
sendChar(ch); //每隔2秒发送每一个字符ch
sleep(2);
}
fclose(fp);
return 0;
}
void sendChar(char ch) //字符发送函数,通过创建ch个进程表示发送字符ch,这些进程持续2秒
{
pid_t fpid; //fpid表示fork函数返回的值
int i;
int count = (int) ch;
printf("***************************************************\n");
printf("Sending [%c], new pid count = [%d].\n", ch, count);
for (i = 0; i < count; i++) //父进程连续创建ch个子进程
{
fpid = fork();
if (fpid < 0)
{
printf("fork error.\n");
}
else if (fpid == 0)
{
printf("Sending [%c], last_pid = %d.\n", ch, getpid());
sleep(2); //这些子进程持续2秒就退出
exit(0);
}
}
}
(6)接收端源代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int bStart = 0;
void writeToFile(char ch);
char receiveChar();
int main()
{
char ch;
int i;
remove("./receiver_text.txt"); //先删除之前接受的文件
while (((ch = receiveChar()) != (char) 0) || bStart == 0)
{ //每隔2秒接受一次字符
if (bStart == 0)
{
printf("Not start.\n"); //bStart为0表示发送端还没开始发送
}
else
{
printf("Write [%c] to file.\n", ch); //接收到发送端发送字符ch
writeToFile(ch); //将ch写入接收文件
}
}
printf("End.\n");
return 0;
}
void writeToFile(char ch) //将ch写入接收文件
{
FILE *fp;
if ((fp = fopen("./receiver_text.txt", "a")) == NULL)
{
printf("fopen error.\n");
exit(0);
}
fputc(ch, fp);
fclose(fp);
}
char receiveChar() //接收字符函数,用间隔2秒的pid差值表示接收字符
{
pid_t fpid1, fpid2; //fpid1, fpid2表示fork函数返回的值
int iDiff;
char ch;
printf("***************************************************\n");
printf("Receiving round begins.\n");
fpid1 = fork();
if (fpid1 < 0)
{
printf("fork error.\n");
}
else if (fpid1 == 0)
{
exit(0);
}
sleep(2);
fpid2 = fork();
if (fpid2 < 0)
{
printf("fork error.\n");
}
else if (fpid2 == 0)
{
exit(0);
}
iDiff = fpid2 - fpid1 - 1; //由于第一次fork占用了一个pid,因此做差时需要减1
ch = (char) iDiff;
if (iDiff < 30) //由于可能有别的新开的进程,导致接收端误以为发送端在发送,因此需要判断,在小于30时,我们认为是误差
{
printf("Receiving round ends. pid_diff = [%d], data is [%c]\n", iDiff, ch);
return (char) 0;
}
else
{
if (bStart == 0) //第一次接收时,由于发送端本身也是一个进程,也占用了一个pid,因此需要减1
{
iDiff--;
ch--;
}
printf("Receiving round ends. pid_diff = [%d], data is [%c]\n", iDiff, ch);
bStart = 1; //更新标识,表示以后就不是第一次接收了
return ch;
}
}
四、实验总结
实验收获:
学到了很多隐蔽通道方面的知识,也进一步熟悉了安胜操作系统的命令用法。
总结实验过程中遇到的问题及解决方法:
在linux中开发C语言程序没有好用的IDE,编程非常不便。
解决方案:
在linux中用samba共享,将linux中的C语言代码共享在Windows下,这样可以在Windows下用Visual Studio等专业IDE对源代码进行编辑,保证了编码工作的高效进行。在编码完成后,用linux的scp工具进行文件传输,如下图所示: