实验目的

选择一个已经标识的隐蔽通道,通过在SecLinux环境中进行实际编程(C语言),完成发送程序、接收程序的编写,并进行收发场景的实际效果演示。

实验内容

  1. 构建测试环境,选择同步机制
  2. 发送和接收程序的编写、编译及运行
  3. 演示存在的隐蔽通道场景

实验准备

  1. 使用 root 进入系统,执行 user_auth 命令获得特权
    image-20201202233515724
    发现证书过期,使用 initcert 命令生成证书
    image-20201202233835926
    再次执行 user_auth 获取特权
    image-20201202234004496
  2. 使用 root 用户创建用户并设置安全级,设置用户密码并设置用户主目录安全级

    $ useradd -m -h SYS_ADMIN -v SYS_ADMIN high
    $ passwd high
    $ useradd -m -h SYS_PUBLIC -v SYS_PUBLIC low
    $ passwd low
    $ setlevel SYS_ADMIN /home/high
    $ setlevel SYS_PUBLIC /home/low
  3. 分别从两个不同终端以 highlow 用户登录
    image-20201203000609160
    使用两个用户设置各自的主目录自主访问权限为0777
    image-20201203000744019
  4. 验证 MAC 策略是否正常
    image-20201203001509329
    说明不可上读

    image-20201203002002474
    说明可以下读,但不能下写

实验过程、结果

同步机制

采用 sleep(秒)/usleep(微秒)制造同步。

当一个进程 sleep 时,就将 cpu 的控制权交给其他进程,直到 sleep 时间已到,重新获得 cpu 的控制权。

实验结果(采用进程标识符信道)

如下面两幅图,左侧为发送端,右侧为接收端,可以看到进程标识符信道较易受到噪声的影响导致接受信息出错。

image-20201203195930913

image-20201203200015595

实验代码(采用进程标识符信道)

发送方代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


pid_t pid[128];
const int sync_time = 3;

void send(char ch){
    int i;
    printf("sending '%c'\n", ch);
    for(i = 0; i < ch; i++){
        pid[i]=fork()
        if(pid[i]==0){
            sleep(1);
            exit(0);
        }
    }
    printf("\tcreate %d processes!\n", ch);
    
}

int main(){
    char ch;
    FILE* f = fopen("in.txt", "r");
    ch = fgetc(f);
    while(1){
        send(ch);
        sleep(sync_time);
        if(ch=='!') break;
        ch = fgetc(f);
    }
    printf("Send Done!\n");
    fclose(f);
}

接收方代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

pid_t firstPid, lastPid;
const int sync_time = 3;

int main(){
    int k = 0;
    char ch;
    FILE *f = fopen('out.txt', 'w');
    if ((firstPid=fork())==0){
        exit(0);
    }
    sleep(1);
    while(1){
        sleep(sync_time);
        if((lastPid=fork())==0){
            exit(0);
        }
        printf('firstPid=%d, lastPid=%d\n', firstPid, lastPid);
        if(k==0){
            ch=lastPid-firstPid-2;
        }else{
            ch=lastPid-firstPid-1;
        }
        printf("\tReceive the '%c'\n", ch);
        fputc(ch, f);
        firstPid = lastPid;
        k=1;
        if(ch == '!') break;
    }
    printf("Receive Done!\n");
    fclose(f);
}

流程图(采用进程标识符信道)

sequenceDiagram
participant Sender
participant Receiver
Receiver ->> Receiver: start, firstPid, sleep 3
Sender ->> Sender: start
loop send message
Sender ->> Sender: read char, create int(char) processes
Sender ->> Receiver: send the char(char)
Receiver ->> Receiver: lastPid, calc char(char), firstPid=lastPid
end
Sender ->> Sender: end
Receiver ->> Receiver: end

实验结果(采用最近访问时间信道)

如下图,左侧为发送端,右侧为接收端,多次实验发现消息传递十分稳定。

image-20201203221126637

实验代码(采用最近访问时间信道)

发送方代码:

#include <stdio.h>
#include <sys/stat.h>

const int sync_time = 5;

void send(char ch){
    int i;
    char file_name[50];
    printf("sending '%c'\n", ch);
    for(i = 0; i < ch; i++){
       sprintf(file_name, "/tmp/%d.txt", i);
       FILE *fp = fopen(file_name, "r");
       fgetc(fp);
       fclose(fp);
    }
    printf("\tvisit %d files!\n", ch);
}

int main(){
    char ch;
    FILE* f = fopen("in.txt", "r");
    ch = fgetc(f);
    while(1){
        send(ch);
        sleep(sync_time);
        if(ch=='!') break;
        ch = fgetc(f);
    }
    printf("Send Done!\n");
    fclose(f);
}

接收方代码:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

const int sync_time = 5;

int main(){
    int i = 0;
    char ch, file_name[50];
    FILE *f = fopen('out.txt', 'w');
    printf("perpare for files in /tmp\n");
    for (i = 0; i < 128; i++){
        sprintf(file_name, "/tmp/%d.txt", i);
        FILE *fp = fopen(file_name, "w");
        fclose(fp);
        chmod(file_name, S_IRWXU|S_IRWXG|S_IRWXO);
    }
    printf("perpare files complete\n");
    while(1){
        sleep(sync_time);
        struct stat buf;
        int old_time = -1, new_time;
        for(i = 0; i< 128; i++){
            sprintf(file_name, "/tmp/%d.txt", i);
            stat(file_name, &buf);
            new_time = buf.st_atime;
            if(old_time != -1 && old_time - new_time > 1){
                ch = (char)i;
                fputc(ch, f);
                printf("\told time: %d, new time: %d\n", old_time, new_time);
                printf("\tReceive the '%c'\n", ch);
                break;
            }
            old_time = new_time;
        }
        
        if(ch == '!') break;
    }
    printf("Receive Done!\n");
    fclose(f);
}

流程图(采用最近访问时间信道)

sequenceDiagram
participant Sender
participant Receiver
Receiver ->> Receiver: start, create files
Sender ->> Sender: start
loop send message
Sender ->> Sender: read char, visit int(char) files
Sender ->> Receiver: send the char(char)
Receiver ->> Receiver: count visited files 
end
Sender ->> Sender: end
Receiver ->> Receiver: end

实验总结

实验收获

对隐蔽通信信道有了更深的了解,进一步熟悉了安胜系统的命令。

实验过程中遇到的问题及解决方法

  1. 虚拟机无法安装 VMware Tools ,只能用 vim 导致编程困难,没有找到好的解决办法。
  2. 使用进程标识符通道时,第一个接收到的字符总是不对,后来发现是由于先运行 receiver 后运行 sender 导致第一次接收时应该用 lastPid-firstPid-2.
  3. 使用最近访问实际通道时,执行发送程序总是提示段错误,原因是接收程序创建的临时文件权限未放开,使用 chmod(file_name, S_IRWXU|S_IRWXG|S_IRWXO) 函数为通信文件设置权限为 777 即可。

总结实验的不足之处,以及进一步的改进措施

  1. 进程标识符通信信道由于较易受到噪声的影响,消息的传递不够稳定,选用其他的隐蔽通信信道如最近访问时间信道进行试验后发现,消息的传递变得稳定。
  2. 代码中采取的睡眠同步技术容易实现,适于演示。但是由于进程发送不同字符所用时间不同,而 sleep 时间一旦指定就是固定的,不能在程序运行期间更改,因此这种同步必然造成时间浪费,改进措施就是选用其他的同步机制,例如作业中提到的最近访问时间的方法。
最后修改:2020 年 12 月 05 日
如果觉得我的文章对你有用,请随意赞赏