-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
0 parents
commit 904029b
Showing
2 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#define _GNU_SOURCE /* See feature_test_macros(7) */ | ||
#include <unistd.h> | ||
#include <sys/syscall.h> /* For SYS_xxx definitions */ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
#include <sys/ptrace.h> | ||
#include <errno.h> | ||
#include <signal.h> | ||
#include <sys/user.h> | ||
#include <syscall.h> | ||
#include <fcntl.h> | ||
#include <stdint.h> | ||
#include <string.h> | ||
#include <stdarg.h> | ||
|
||
#include <regex.h> | ||
|
||
typedef uint64_t u64; | ||
typedef int64_t s64; | ||
|
||
/* from include/linux/dirent.h : */ | ||
|
||
struct linux_dirent64 { | ||
u64 d_ino; | ||
s64 d_off; | ||
unsigned short d_reclen; | ||
unsigned char d_type; | ||
char d_name[0]; | ||
}; | ||
|
||
void die(char *fmt,...) { | ||
va_list ap; | ||
va_start(ap,fmt); | ||
vfprintf(stderr,fmt,ap); | ||
exit(1); | ||
} | ||
|
||
void die_regerror(int status,regex_t *re) { | ||
char msg[80]; | ||
int s; | ||
s=regerror(status,re,msg,sizeof(msg)); | ||
die("regex: %s\n",msg); | ||
} | ||
|
||
int hostnum(char *hostname) { | ||
static regex_t *re=NULL; | ||
int status; | ||
regmatch_t match[2]; | ||
|
||
if (!re) { | ||
re=malloc(sizeof(*re)); | ||
if (!re) die(""); | ||
status=regcomp(re,"^host([0-9]+)$",REG_EXTENDED); | ||
if (status) die_regerror(status,re); | ||
} | ||
|
||
status=regexec(re,hostname,sizeof(match)/sizeof(*match),match,0); | ||
if (status==0) { | ||
char c=hostname[match[1].rm_eo]; | ||
match[1].rm_eo='\0'; | ||
int num=atoi(&hostname[match[1].rm_so]); | ||
match[1].rm_eo=c; | ||
return(num); | ||
} else if (status==REG_NOMATCH) { | ||
return(-1); | ||
} else { | ||
die_regerror(status,re); | ||
} | ||
} | ||
|
||
struct sortentry { | ||
struct linux_dirent64 *dirent; | ||
int hostnum; | ||
}; | ||
|
||
int compare_sortentry(const void *vp1,const void *vp2) { | ||
struct sortentry *p1=(struct sortentry *)vp1; | ||
struct sortentry *p2=(struct sortentry *)vp2; | ||
|
||
if (p1->hostnum!=-1 && p2->hostnum!=-1) { | ||
return p1->hostnum<p2->hostnum ? -1 : p1->hostnum>p2->hostnum ? 1 : 0; | ||
} | ||
return strcmp(p1->dirent->d_name,p2->dirent->d_name); | ||
} | ||
|
||
void fix_memory(pid_t pid,size_t count,void *dirp) { | ||
|
||
char *memfilename; | ||
int fd; | ||
|
||
char *dirents_unsorted,*dirents_sorted; | ||
struct sortentry *sort_array; | ||
struct sortentry *sort_entry; | ||
|
||
size_t s; | ||
|
||
int entry_count; | ||
int bpos; | ||
int i; | ||
|
||
struct linux_dirent64 *d; | ||
|
||
if (count==0) return; | ||
|
||
if (asprintf(&memfilename,"/proc/%d/mem",pid)==-1) die("%m\n"); | ||
|
||
fd=open(memfilename,O_RDWR); | ||
if (fd==-1) die (memfilename); | ||
|
||
dirents_unsorted=malloc(count); | ||
if(!dirents_unsorted) die (""); | ||
|
||
if (lseek(fd,(off_t)dirp,SEEK_SET)<-1) die("%s: %m\n",memfilename); | ||
s=read(fd,dirents_unsorted,count); | ||
if (s == -1) die("%s: %m\n",memfilename); | ||
if (s != count) die("short reads on childs memory not implemented"); | ||
|
||
entry_count=0; | ||
for (bpos=0;bpos<count;) { | ||
d = (struct linux_dirent64 *) (dirents_unsorted + bpos); | ||
entry_count++; | ||
bpos+=d->d_reclen; | ||
} | ||
|
||
sort_array=malloc(entry_count*sizeof (*sort_array)); | ||
if (!sort_array) die (""); | ||
|
||
sort_entry=sort_array; | ||
for (bpos=0;bpos<count;) { | ||
d = (struct linux_dirent64 *) (dirents_unsorted + bpos); | ||
sort_entry->dirent=d; | ||
sort_entry->hostnum=hostnum(d->d_name); | ||
sort_entry++; | ||
bpos+=d->d_reclen; | ||
} | ||
|
||
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); } | ||
|
||
qsort(sort_array,entry_count,sizeof(*sort_array),compare_sortentry); | ||
|
||
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); } | ||
|
||
dirents_sorted=malloc(count); | ||
if(!dirents_sorted) die ("%m\n"); | ||
|
||
bpos=0; | ||
for (i=0;i<entry_count;i++) { | ||
d = (struct linux_dirent64 *) (dirents_sorted + bpos); | ||
memcpy(d,sort_array[i].dirent,sort_array[i].dirent->d_reclen); | ||
bpos+=sort_array[i].dirent->d_reclen; | ||
} | ||
|
||
// for (bpos=0;bpos<count;) { d = (struct linux_dirent64 *) (dirents_sorted + bpos); printf(" --> %s\n",d->d_name); bpos+=d->d_reclen; } | ||
|
||
if (lseek(fd,(off_t)dirp,SEEK_SET)<-1) die("%s: %m\n",memfilename); | ||
s=write(fd,dirents_sorted,count); | ||
if (s == -1) die(memfilename); | ||
if (s != count) die("internal error: short write"); | ||
|
||
close(fd); | ||
|
||
free(memfilename); | ||
free(dirents_unsorted); | ||
free(dirents_sorted); | ||
free(sort_array); | ||
} | ||
|
||
int main(int argc, char **argv) { | ||
pid_t pid; | ||
int status; | ||
int syscall_state=0; | ||
struct user user; | ||
|
||
static const char *TW_CLI_ORIG="/root/bin/tw_cli.exe"; | ||
|
||
pid=fork(); | ||
if (pid==0) { | ||
if (ptrace(PTRACE_TRACEME,NULL,NULL)==-1) die("ptrace: %m\n"); | ||
execv(TW_CLI_ORIG,argv); | ||
die("%s: %m\n",TW_CLI_ORIG); | ||
} else if (pid==-1) { | ||
die("fork: %m\n"); | ||
} | ||
|
||
while(1) { | ||
pid=wait(&status); | ||
if (pid==-1) die("wait: %m\n"); | ||
if (WIFSIGNALED(status)) { | ||
int signal=WTERMSIG(status); | ||
die("child got signal %d - exiting\n",signal); | ||
} else if (WIFSTOPPED(status)) { | ||
int signal=WSTOPSIG(status); | ||
if (signal==SIGTRAP) { | ||
if(ptrace(PTRACE_SETOPTIONS,pid,NULL,PTRACE_O_TRACESYSGOOD)==-1) die("ptrace: %m\n"); | ||
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die ("ptrace: %m\n"); | ||
} else if (signal==SIGTRAP|0x80) { | ||
if (syscall_state==1) { | ||
if(ptrace(PTRACE_GETREGS,pid,NULL,&user)==-1) die("ptrace: %m\n");; | ||
|
||
/* the 0xFF is not right but rax is 0xffffffffffffffda , _NR_getdents64 is 217 which is 0xda | ||
* and the syscall interface somehow fixes is */ | ||
|
||
if ((unsigned char)(user.regs.orig_rax & 0xFF) == SYS_getdents64) { | ||
fix_memory(pid,(int)user.regs.rax,(void *)user.regs.rsi); | ||
} | ||
} | ||
syscall_state=1-syscall_state; | ||
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die("ptrace: %m\n");; | ||
} else { | ||
die("child stopped by signal %d - exiting\n",signal); | ||
} | ||
} else if (WIFEXITED(status)) { | ||
if (WEXITSTATUS(status)) { | ||
exit(1); | ||
} else { | ||
exit(0); | ||
} | ||
} else { | ||
die("unexpected return from wait. status=%08x - exiting\n",status); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#! /usr/bin/perl | ||
use strict; | ||
use warnings; | ||
|
||
sub sort_host { | ||
my ($n1,$n2); | ||
($n1)=$a=~/^host(\d+)$/ and ($n2)=$b=~/^host(\d+)$/ and return $n1 <=> $n2; | ||
return $a cmp $b; | ||
} | ||
|
||
|
||
our $SYS_unshare=272; # /usr/include/asm/unistd_64.h | ||
our $CLONE_NEWNS=0x20000; # /usr/include/linux/sched.h | ||
|
||
my $pid=fork; | ||
defined $pid or die "$!\n"; | ||
unless ($pid) { | ||
opendir my $d,"/sys/class/scsi_host"; | ||
my @names=sort sort_host grep !/^\.\.?$/,readdir $d; | ||
|
||
syscall($SYS_unshare,$CLONE_NEWNS) and die "$!\n"; | ||
-d '/tmp/sysfs' or mkdir("/tmp/sysfs") or die "/tmp/sysfs: $!\n"; | ||
system 'mount','-tsysfs','BLA','/tmp/sysfs' and exit 1; | ||
system 'mount','-ttmpfs','BLA','/sys/class/scsi_host' and exit 1; | ||
|
||
for my $name (reverse @names) { | ||
symlink("/tmp/sysfs/class/scsi_host/$name","/sys/class/scsi_host/$name") or die "/sys/class/scsi_host/$name: $!\n"; | ||
} | ||
exec '/home/buczek/tw_cli/tw_cli.orig',@ARGV; | ||
die "$!\n"; | ||
} | ||
wait; | ||
$? and exit 1; | ||
|
||
|