Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
donald committed Nov 12, 2016
0 parents commit 904029b
Showing 2 changed files with 260 additions and 0 deletions.
225 changes: 225 additions & 0 deletions tw_cli.c
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);
}
}
}

35 changes: 35 additions & 0 deletions tw_cli.pl
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;


0 comments on commit 904029b

Please sign in to comment.