writing a kernel module alternative to existing one

Hello fellows,

I'm new to writing a FreeBSD kernel module and want your help to port the following linux kernel module.

The module itself does: starts a new thread and calls run_it which uses an integer and char arrays to store the processes pid and their commands. Outputs only the new non existing pids and commands to dmesg and fills the integer and char arrays too with the new pids/commands. Upon reaching 999 or more entries we reset the arrays to 0 and store the new entries in them.

So my question is: How do I start/stop a new thread with the desired function name upon loading/unloading the module ? How do I sleep within the thread ? How do I print the desired information to dmesg ?

Here's the linux module:

C:
/*
   08/16/2018

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/udp.h>
#include <linux/mm.h>
#include <linux/kthread.h>
#include <linux/pid.h>

unsigned int quit = 0U;
struct task_struct *thread;

static int run_it(void *data) {
  static unsigned int x = 0U;
  static unsigned int idx = 0U;
  static unsigned int skip = 0U;
  static unsigned int i_arr[1000] = {0U};
  static char c_arr[1000][256] = {""};

  while (1) {
    struct task_struct *task = NULL;
    if (1U == quit) {
      break;
    }
    for_each_process(task) {
      if (idx >= 999U) {
        memset(i_arr, 0, sizeof(i_arr));
        memset(c_arr, 0, sizeof(c_arr));
        idx = 0U;
      }
      for (x = 0U; x <= idx; x++) {
        if (i_arr[x] == (unsigned int)(task->pid) && 0 == (strcmp(task->comm, c_arr[x]))) {
          skip = 1U;
          break;
        }
      }
      if (0 == (strcmp(task->comm, "")) ||
          (int)pid_nr(get_task_pid(thread, PIDTYPE_PID)) == task->pid) {
        skip = 1U;
      }
      if (1U != skip) {
        i_arr[idx] = (unsigned int)task->pid;
        snprintf(c_arr[idx], 255, "%s", task->comm);

        printk("%d %s\n", task->pid, task->comm);
        idx++;
      }
      skip = 0U;
      schedule();
    }
    ssleep(5);
  }
  do_exit(0);
  return 0;
}

static int __init init_hello(void) {
  thread = kthread_run(run_it, NULL, "list processes");
  if (thread) {
    wake_up_process(thread);
  }
  return 0;
}

static void __exit init_exit(void) {
  quit = 1U;
  kthread_stop(thread);
}

module_init(init_hello);
module_exit(init_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("su8");
MODULE_DESCRIPTION("List all processes and log them to dmesg");

and here's the FreeBSD code that replaces the linux for_each_process:

C:
/*
   09/03/2018

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.
*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <kvm.h>

int main (void) {
  struct kinfo_proc *kp = NULL;
  int x = 1;
  int count = 0;
  FILE *fp = NULL;
  kvm_t *kd = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, "error: ");

  if (NULL == kd) {
    return EXIT_FAILURE;
  }
  if (NULL == (fp = fopen("/tmp/log", "a"))) {
    goto err;
  }

  kp = kvm_getprocs(kd, KERN_PROC_PROC, 0, &count);
  for (; x < count; x++) {
    fprintf(fp, "%d %s\n", kp[x].ki_pid, kp[x].ki_comm);
  }

err:
  if (NULL != fp) {
    fclose(fp);
  }
  kvm_close(kd);
  return EXIT_SUCCESS;
}
 
Here's what I came up with, gathered from several sources, but the code that runs in infinite loop never uses the new thread, so I get stuck in kldload mymodule:

C:
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kthread.h>

static unsigned int quit = 0U;
static struct proc *mainproc = NULL;

static void main_thread(void *arg) {
  while (1) {
    if (1U == quit) {
      break;
    }
  }
  kthread_exit();
}

static void proc_routine(void *arg) {
  struct thread *td = curthread;
  struct proc *p = td->td_proc;
  struct thread *ntd = NULL;
  kthread_add(main_thread, NULL, p, &ntd, 0, 0, "kthread");
  kproc_exit(0);
}

static int EventHandler(struct module *inModule, int inEvent, void *inArg) {
  switch (inEvent) {
    case MOD_LOAD: {
      kproc_create(proc_routine, NULL, &mainproc, 0, 0, "proc list looper");
    }
    break;
  case MOD_UNLOAD:
    quit = 1U;
    break;
  default:
    break;
  }
  return 0;
}

static moduledata_t moduleData = {
  "hello_world_kmod",     // Module Name
  EventHandler,           // Event handler function name
  NULL                    // Extra data
};

DECLARE_MODULE(hello_world_kmod, moduleData, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
 
When writing kernel modules, you should really read "The Design And Implementation Of The FreeBSD Operation System".

What you are doing here looks rather fishy to me...
 
Back
Top