下午好,我的目标是编写一个 C 程序,当被调用时,它会运行另一个给定的程序并尝试控制子进程的行为。
如果孩子打开任何文件(除了预先打开的文件 stdin、stdout、stderr 之外),这应该被阻止并且程序应该被终止。
我编写了以下程序来实现上述程序要求。好消息是,只有在我从 KITTY 会话重新启动 LINUX 操作系统后运行我的程序时,我的程序才会始终拦截当孩子打开任何文件(预打开的文件 stdin、stdout、stderr 除外)时生成的 SIGIO 信号。问题是,在我的程序第一次成功运行后,它在后续尝试拦截 SIGIO 信号时失败。请告诉我我在程序中做错了什么以及如何解决它。
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/sysinfo.h>
#include <pthread.h>
#include <sys/ptrace.h>
#define MAXLINE 256
#define MAXARGS 128
#define SHELL "/h/fchang03"
#define READ 0
#define WRITE 1
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int fd[2];
pthread_spinlock_t spinlock;
struct statStuff {
int pid; // %d
char comm[256]; // %s
char state; // %c
int ppid; // %d
int pgrp; // %d
int session; // %d
int tty_nr; // %d
int tpgid; // %d
unsigned long flags; // %lu
unsigned long minflt; // %lu
unsigned long cminflt; // %lu
unsigned long majflt; // %lu
unsigned long cmajflt; // %lu
unsigned long utime; // %lu
unsigned long stime; // %lu
long cutime; // %ld
long cstime; // %ld
long priority; // %ld
long nice; // %ld
long num_threads; // %ld
long itrealvalue; // %ld
unsigned long starttime; // %lu
unsigned long vsize; // %lu
long rss; // %ld
unsigned long rlim; // %lu
unsigned long startcode; // %lu
unsigned long endcode; // %lu
unsigned long startstack; // %lu
unsigned long kstkesp; // %lu
unsigned long kstkeip; // %lu
unsigned long signal; // %lu
unsigned long blocked; // %lu
unsigned long sigignore; // %lu
unsigned long sigcatch; // %lu
unsigned long wchan; // %lu
unsigned long nswap; // %lu
unsigned long cnswap; // %lu
int exit_signal; // %d
int processor; // %d
unsigned long rt_priority; // %lu
unsigned long policy; // %lu
unsigned long long delayacct_blkio_ticks; // %llu
} ;
static int readStat(int pid, struct statStuff *s) {
const char *format = "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu";
char buf[256];
FILE *proc;
sprintf(buf,"/proc/%d/stat",pid);
proc = fopen(buf,"r");
if (proc) {
if (42==fscanf(proc, format,
&s->pid,
s->comm,
&s->state,
&s->ppid,
&s->pgrp,
&s->session,
&s->tty_nr,
&s->tpgid,
&s->flags,
&s->minflt,
&s->cminflt,
&s->majflt,
&s->cmajflt,
&s->utime,
&s->stime,
&s->cutime,
&s->cstime,
&s->priority,
&s->nice,
&s->num_threads,
&s->itrealvalue,
&s->starttime,
&s->vsize,
&s->rss,
&s->rlim,
&s->startcode,
&s->endcode,
&s->startstack,
&s->kstkesp,
&s->kstkeip,
&s->signal,
&s->blocked,
&s->sigignore,
&s->sigcatch,
&s->wchan,
&s->nswap,
&s->cnswap,
&s->exit_signal,
&s->processor,
&s->rt_priority,
&s->policy,
&s->delayacct_blkio_ticks
)) {
printf("Group Number = %d\n",s->session);
printf("Stack start = %x\n",s->startstack);
printf("Stack end = %x\n",s->kstkesp);
fclose(proc);
return s->session;
} else {
fclose(proc);
return 0;
}
} else {
return 0;
}
}
int eval(const char *cmdline)
{
char *argv[MAXARGS];
int bg;
pid_t pid;
int status;
struct statStuff test;
int value;
FILE* fp;
struct rusage usage;
pid = fork();
if (pid > 0){
/* This is the child process. */
char* p;
int num_procs;
int n_bytes = 256;
int bytes_read;
char buffer[1024];
char stuff[256];
char* ptr;
struct rlimit rl;
int x;
sscanf(cmdline,"%s %d",stuff,&x);
rl.rlim_cur = 15;
rl.rlim_max = 15;
setrlimit(RLIMIT_NPROC,&rl);
ptr = 0;
if (x == 0){
sprintf(buffer,"/proc/%d/stat",pid);
}
else{
sprintf(buffer,"/proc/%d/stat",x);
}
int fd = open(buffer,O_RDONLY);
while (read(fd,buffer,256) > 0){
sprintf(cmdline,"%s %d",stuff,readStat(x,&test));
printf("CMDLINE = %s\n",cmdline);
eval(cmdline);
lseek(fd,256,SEEK_CUR);
}
close(fd);
wait3(&status,0,&usage);
exit(1);
}
else if (pid < 0){
/* The fork failed. Report failure. */
status = -1;
}
else{
close(fd[READ]);
close(fileno(stdout));
dup(fd[WRITE]);
fcntl(0,F_SETFL,O_ASYNC);
fcntl(1,F_SETFL,O_ASYNC);
fcntl(2,F_SETFL,O_ASYNC);
fcntl(3,F_SETFL,O_ASYNC);
execl("/h/fchang03/five","five",0);
perror("execl");
}
return 0;
}
void *reader(int signal)
{
pid_t pid1,pid2;
int status;
int fd[2];
char buf[256];
char buffer[256];
char filename[256];
char dbgfilename[256];
int myfd;
int length;
struct rusage usage;
// printf("SIGNAl %d received\n",signal);
printf("%s"," ");
length = 256;
if (signal == 0){
return NULL;
}
pipe(fd);
if ((pid1 = fork())) { /* child subprocess */
pthread_spin_lock(&spinlock);
sprintf(filename,"/proc/%d/fdinfo/1",pid1);
myfd = open(filename,O_RDONLY);
pthread_spin_unlock(&spinlock);
if (myfd == -1){
printf("myfd = %d filename = %s\n",myfd,filename);
perror("myerror");
exit(1);
}
fcntl(0,F_SETOWN,getpid());
fcntl(1,F_SETOWN,getpid());
fcntl(2,F_SETOWN,getpid());
fcntl(3,F_SETOWN,getpid());
if (signal == SIGIO){
printf("SIGNAL SIGIO RECEIVED");
kill(pid1,SIGKILL);
}
close(myfd);
close(fd[WRITE]);
FILE *read = fdopen(fd[READ],"r");
while (!feof(read)) {
fgets(buf,256,read);
}
close(fd[READ]);
pid2 = wait3(&status,0, &usage);
if (signal == SIGKILL){
exit(1);
}
}
else {
close(fd[READ]);
close(fileno(stdout));
dup(fd[WRITE]);
// child only unblock mask
fcntl(0, F_SETFL, O_ASYNC);
fcntl(1, F_SETFL, O_ASYNC);
fcntl(2, F_SETFL, O_ASYNC);
fcntl(3, F_SETFL, O_ASYNC);
execl("/h/fchang03/five","five",NULL);
}
}
int main(void)
{
pthread_t tid1,tid2;
char cmdline[MAXLINE];
char temp[MAXLINE];
int start;
struct sigaction set,myset;
pthread_t thread;
pthread_t thread2;
sigemptyset(&set);
sigemptyset(&myset);
memset(&set,0,sizeof(struct sigaction));
memset(&myset,0,sizeof(struct sigaction));
sigaddset(&set.sa_mask, SIGINT);
sigaddset(&set.sa_mask, SIGCHLD);
sigaddset(&set.sa_mask, SIGIO);
set.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
set.sa_handler = reader;
sigaddset(&myset.sa_mask, SIGIO);
myset.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
myset.sa_handler = reader;
sigprocmask(SIG_UNBLOCK, &myset, &set); // later explicitly just unblock SIGIO
sigaction(SIGCHLD,&myset,&set);
sigaction(SIGIO,&myset,&set);
pthread_spin_init(&spinlock, 0);
pthread_create(&tid1,NULL,reader,NULL);
pthread_create(&tid2,NULL,reader,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
start = 0;
while (1){
printf("> ");
fgets(temp, MAXLINE, stdin);
sprintf(cmdline,"./%s %d",temp,start);
if (feof(stdin)){
exit(0);
}
if (eval(cmdline) == -1){
break;
}
}
}