libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

linux_rb.c (5425B)


      1 // gcc -I/usr/include/ruby-3.0.0/x86_64-linux -I/usr/include/ruby-3.0.0/ruby/backward -I/usr/include/ruby-3.0.0 -shared -fPIC -o linux_rb.so linux_rb.c
      2 
      3 #include <ruby.h>
      4 
      5 #include <linux/sched.h>    /* Definition of struct clone_args */
      6 #include <sched.h>          /* Definition of CLONE_* constants */
      7 #include <sys/syscall.h>    /* Definition of SYS_* constants */
      8 #include <unistd.h>
      9 #include <signal.h>
     10 #include <errno.h>
     11 #include <sys/mount.h>
     12 #include <sys/socket.h>
     13 #include <netinet/ip.h>
     14 #include <net/if.h>
     15 
     16 #include <sys/mman.h>
     17 
     18 static volatile _Thread_local unsigned long long clone_flags =
     19   CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID;
     20 static pid_t fork_hijack()
     21 {
     22   struct clone_args ca = {
     23     .flags = clone_flags,
     24     .exit_signal = SIGCHLD,
     25   };
     26   clone_flags = CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID;
     27   return syscall(SYS_clone3, &ca, sizeof(ca));
     28 }
     29 
     30 static void hijack_fork()
     31 {
     32   char* ptr = (char*) &_Fork;
     33   void* page = (void*) (((uintptr_t) ptr) & ~4095);
     34   mprotect(page, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
     35   ptr[0] = 0xe9;
     36   *(uint32_t*)(ptr+1) = (uintptr_t) &fork_hijack - (uintptr_t) (ptr+5);
     37   mprotect(page, 4096, PROT_READ | PROT_EXEC);
     38 }
     39 
     40 static VALUE rb_clone(VALUE obj, VALUE flags)
     41 {
     42   unsigned long long old_flags = flags;
     43   clone_flags = RB_NUM2LONG(flags);
     44   pid_t pid = NUM2PIDT(rb_funcall(rb_mProcess, rb_intern("_fork"), 0));
     45 
     46   switch (pid)
     47   {
     48   case 0:
     49     if (rb_block_given_p())
     50     {
     51       int status;
     52       rb_protect(rb_yield, Qundef, &status);
     53       ruby_stop(status);
     54     }
     55     return Qnil;
     56 
     57   case -1:
     58     rb_sys_fail("clone3");
     59     return Qnil;
     60 
     61   default:
     62     return PIDT2NUM(pid);
     63   }
     64 }
     65 
     66 static VALUE rb_unshare(VALUE self, VALUE flags)
     67 {
     68   if (unshare(RB_NUM2INT(flags)) != 0)
     69     rb_sys_fail("unshare");
     70   return Qnil;
     71 }
     72 
     73 #define MAYBE_CSTR(x) ((x) == Qnil ? NULL : StringValueCStr(x))
     74 static VALUE rb_mount(int argc, VALUE* argv, VALUE self)
     75 {
     76   VALUE src, tgt, fstype, flags, opts;
     77   rb_scan_args(argc, argv, "32", &src, &tgt, &fstype, &flags, &opts);
     78   if (mount(MAYBE_CSTR(src), MAYBE_CSTR(tgt), MAYBE_CSTR(fstype),
     79             flags == Qnil ? 0 : RB_NUM2ULONG(flags), MAYBE_CSTR(opts)) != 0)
     80     rb_sys_fail("mount");
     81   return Qnil;
     82 }
     83 
     84 static VALUE rb_umount(VALUE self, VALUE path, VALUE flags)
     85 {
     86   if (umount2(StringValueCStr(path), RB_NUM2INT(flags)) != 0)
     87     rb_sys_fail("umount2");
     88   return Qnil;
     89 }
     90 
     91 static VALUE rb_gethostname(VALUE self)
     92 {
     93   char buf[HOST_NAME_MAX+1];
     94   if (gethostname(buf, HOST_NAME_MAX) != 0)
     95     rb_sys_fail("gethostname");
     96   buf[HOST_NAME_MAX] = '\0';
     97   return rb_str_new_cstr(buf);
     98 }
     99 
    100 static VALUE rb_sethostname(VALUE self, VALUE name)
    101 {
    102   Check_Type(name, RUBY_T_STRING);
    103   if (sethostname(RSTRING_PTR(name), RSTRING_LEN(name)) != 0)
    104     rb_sys_fail("sethostname");
    105   return Qnil;
    106 }
    107 
    108 static VALUE rb_getdomainname(VALUE self)
    109 {
    110   char buf[65];
    111   if (getdomainname(buf, 64) != 0)
    112     rb_sys_fail("getdomainname");
    113   buf[64] = '\0';
    114   return rb_str_new_cstr(buf);
    115 }
    116 
    117 static VALUE rb_setdomainname(VALUE self, VALUE name)
    118 {
    119   Check_Type(name, RUBY_T_STRING);
    120   if (setdomainname(RSTRING_PTR(name), RSTRING_LEN(name)) != 0)
    121     rb_sys_fail("setdomainname");
    122   return Qnil;
    123 }
    124 
    125 static VALUE rb_up_lo(VALUE self)
    126 {
    127   int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    128   if (fd == -1) rb_sys_fail("socket");
    129 
    130   struct ifreq req;
    131   memset(&req, 0, sizeof(req));
    132   strncpy(req.ifr_name, "lo", IFNAMSIZ);
    133   req.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
    134   int res = ioctl(fd, SIOCSIFFLAGS, &req);
    135   int errsav = errno;
    136   close(fd);
    137 
    138   if (res != 0)
    139   {
    140     errno = errsav;
    141     rb_sys_fail("ioctl");
    142   }
    143   return Qnil;
    144 }
    145 
    146 static VALUE rb_pivot_root(VALUE self, VALUE new, VALUE old)
    147 {
    148   if (syscall(SYS_pivot_root, StringValueCStr(new), StringValueCStr(old)) != 0)
    149     rb_sys_fail("pivot_root");
    150   return Qnil;
    151 }
    152 
    153 void Init_linux_rb(void)
    154 {
    155   hijack_fork();
    156 
    157   VALUE mod = rb_define_module("Linux");
    158 #define DEF(name, fun, arity) \
    159   rb_define_singleton_method(mod, name, fun, arity); \
    160   rb_define_module_function(mod, name, fun, arity)
    161 
    162   DEF("clone", rb_clone, 1);
    163   DEF("unshare", rb_unshare, 1);
    164   DEF("mount", rb_mount, -1);
    165   DEF("umount", rb_umount, 2);
    166   DEF("up_lo", rb_up_lo, 0);
    167   DEF("hostname", rb_gethostname, 0);
    168   DEF("hostname=", rb_sethostname, 1);
    169   DEF("domainname", rb_getdomainname, 0);
    170   DEF("domainname=", rb_setdomainname, 1);
    171   DEF("pivot_root", rb_pivot_root, 2);
    172 #undef DEF
    173 
    174 #define C(x) rb_define_const(mod, #x, RB_LONG2NUM(x))
    175   C(CLONE_VM); C(CLONE_FS); C(CLONE_FILES); C(CLONE_SIGHAND); C(CLONE_PIDFD);
    176   C(CLONE_PTRACE); C(CLONE_VFORK); C(CLONE_PARENT); C(CLONE_THREAD);
    177   C(CLONE_NEWNS); C(CLONE_SYSVSEM); C(CLONE_SETTLS); C(CLONE_PARENT_SETTID);
    178   C(CLONE_CHILD_CLEARTID); C(CLONE_DETACHED); C(CLONE_UNTRACED);
    179   C(CLONE_CHILD_SETTID); C(CLONE_NEWCGROUP); C(CLONE_NEWUTS); C(CLONE_NEWIPC);
    180   C(CLONE_NEWUSER); C(CLONE_NEWPID); C(CLONE_NEWNET); C(CLONE_IO);
    181 
    182   C(MS_RDONLY); C(MS_NOSUID); C(MS_NODEV); C(MS_NOEXEC); C(MS_SYNCHRONOUS);
    183   C(MS_REMOUNT); C(MS_MANDLOCK); C(MS_DIRSYNC);
    184 #ifdef MS_NOSYMFOLLOW
    185   C(MS_NOSYMFOLLOW);
    186 #endif
    187   C(MS_NOATIME); C(MS_NODIRATIME); C(MS_BIND); C(MS_MOVE); C(MS_REC);
    188   C(MS_SILENT); C(MS_POSIXACL); C(MS_UNBINDABLE); C(MS_PRIVATE); C(MS_SLAVE);
    189   C(MS_SHARED); C(MS_RELATIME); C(MS_KERNMOUNT); C(MS_I_VERSION);
    190   C(MS_STRICTATIME); C(MS_LAZYTIME); C(MS_ACTIVE); C(MS_NOUSER);
    191 
    192   C(MNT_FORCE); C(MNT_DETACH); C(MNT_EXPIRE); C(UMOUNT_NOFOLLOW);
    193 #undef C
    194 }