Thursday, December 25, 2014

Procfs basics, Standard procfs files, Steps to create custom procfs file


In this post, I will cover basics of procfs, overview of standard procfs files and and steps to create custom proc entries.

procfs - Basics

procfs is a RAM based file system mounted at /proc. procfs is a communication mechanism between linux user space & kernel space. From user space, procfs files can be read to view information in kernel's internal data structures & written into to modify information in kernel's internal data structures. By using a RAM based file system, the well established file system interface is leveraged rather than create yet another specific interface.

Standard procfs files

  • Process specific entries: Linux kernel uses procfs to export (and also to receive user inputs) info about it's processes. Each process has a file named /proc/<pid>. Here is the list of files/sub-directories in process with pid 1:


root@babu-VirtualBox:/proc/1# ls
attr                          cpuset           limits             net                        sched           syscall
autogroup                cwd               loginuid          ns                         schedstat      task
auxv                        environ          map_files       oom_adj                sessionid      timers
cgroup                     exe                maps             oom_score             smaps          wchan
clear_refs                fd                  mem              oom_score_adj      stack
cmdline                   fdinfo            mountinfo      pagemap                stat
comm                      io                  mounts          personality             statm
coredump_filter      latency          mountstats     root                       status
root@babu-VirtualBox:/proc/1# 
I will not delve into the details of each file above. In some of my earlier posts, I displayed contents of some of the above files such as /proc/<pid>/smaps etc.
  • Kernel Data: Apart from process specific directories, /proc contains various other files offering insight into kernel's data structures:

root@babu-VirtualBox:/proc# ls | grep -v '^[0-9]' | column -x
acpi                             asound                       buddyinfo
bus                              cgroups                      cmdline
consoles                      cpuinfo                      crypto
devices                       diskstats                     dma
dri                               driver                         execdomains
fb                                filesystems                 fs
interrupts                    iomem                        ioports
irq                               kallsyms                     kcore
key-users                    kmsg                           kpagecount
kpageflags                  latency_stats               loadavg
locks                            lttng                            mdstat
meminfo                     misc                            modules
mounts                       mtrr                            net
pagetypeinfo              partitions                   sched_debug
schedstat                    scsi                              self
slabinfo                      softirqs                       stat
swaps                         sys                               sysrq-trigger
sysvipc                        timer_list                    timer_stats
tty                               uptime                        version
version_signature      vmallocinfo                vmstat
zoneinfo
root@babu-VirtualBox:/proc# 
I will not delve into the details of each file above. In some of my earlier posts, I displayed contents of some of the above files such as /proc/meminfo, /proc/slabinfo, /proc/buddyinfo etc.
  • Networking Info: /proc/net - TBD
  • IDE devices info : /proc/ide - TBD
  • SCSI devices info: /proc/scsi - TBD
  • Parallel port info: /proc/parport - TBD
  • tty info: /proc/tty - TBD
  • File System Info: /proc/fs - TBD
  • Console Info: /proc/consoles - TBD

Steps to create Custom procfs files

Kernel modules too can leverage procfs to display the information about their data structures as well as to get configuration info inputs from user.

procfs APIs have two versions - legacy version & latest version. The legacy version is deprecated in kernel versions >= 3.10. I will cover details of latest version in this post. The latest version is useful for kernel versions >= 3.13 .... 

  • How to create a new proc directory?
#define PROC_TEST_DIR "test"
        /*Create a new directory named PROC_TEST_DIR in /proc */
        proc_test_dir = proc_mkdir(PROC_TEST_DIR, NULL);
        if (!proc_test_dir)
        {
            printk("PROC_TEST_DIR creation failed.. Exiting. \r\n");
            return -1;
        }

  • How to create a new proc file? 

#define PROC_TEST_CONFIG_FILE "config"
        /* Create a new proc file in PROC_TEST_DIR in "rw- r-- r--" mode*/
        proc_test_config = proc_create(PROC_TEST_CONFIG_FILE, 0644,
                                proc_test_dir, &proc_test_config_file_ops);
        if (proc_test_dir == NULL) {
                printk("Could not create /proc/%s/%s\n", PROC_TEST_DIR,
                       PROC_TEST_CONFIG_FILE);
                remove_proc_entry(PROC_TEST_DIR, NULL);
                return -1;
        }

  • Reading APIs: Creating file alone is not sufficient. We need to write callback handlers that actually read/write into the module's data structures. Here is the code from the example code that displays it's data structures through procfs (reading from kernel module). This code uses seq_file interface. I will cover details of this interface in another blog post:


static void *proc_test_config_start(struct seq_file *, loff_t *);
static void *proc_test_config_next(struct seq_file *, void *, loff_t *);
static void proc_test_config_stop(struct seq_file *, void *);
static int proc_test_config_read(struct seq_file *, void *);
static struct seq_operations proc_test_config_seq_op = {
        .start =        proc_test_config_start,
        .next =         proc_test_config_next,
        .stop =         proc_test_config_stop,
        .show =         proc_test_config_read
};
static int proc_test_config_open(struct inode *inode, struct file *file)
{
        return seq_open(file, &proc_test_config_seq_op);
}
/**
 * This function is called at the beginning of a sequence.
 * ie, when:
 *      - the /proc file is read (first time)
 *      - after the function stop (end of sequence)
 *
 */
static void *proc_test_config_start(struct seq_file *m, loff_t * pos)
{
        static int cur_array_num=1, entry_num = 0;
        /* beginning a new sequence ? */
        if (*pos == 0) {
//printk("seq_start invoked at beg of first sequence \r\n");
                m->private = (void *)&cur_array_num;
                seq_printf(m, "\n\nConfig 1 Info:\n");
                seq_printf(m, "----------------------------\n");
                /* yes => return a non null value to begin the sequence */
                return &entry_num;
        } else if (*pos == 1) {
//printk("\n\nseq_start invoked at beg of second sequence \r\n");
                cur_array_num++;
                entry_num=0;
                m->private = (void *)&cur_array_num;
                seq_printf(m, "\n\nConfig 2 Info:\n");
                seq_printf(m, "----------------------------\n");
                /* yes => return a non null value to begin the sequence */
                return &entry_num;
        } else {
                /* no => it's the end of the sequence, return end to stop reading */
//printk("seq_start invoked at end of sequence \r\n");
                *pos = 0;
                cur_array_num=0;
                return NULL;
        }
}
/**
 * This function is called after the beginning of a sequence.
 * It's called untill the return is NULL (this ends the sequence).
 *
 */
static void *proc_test_config_next(struct seq_file *m, void *entry_num,
        loff_t * pos)
{
    int cur_array_num=*((int *)m->private);
    if (cur_array_num == 1)
    {
//printk("seq_next invoked in first sequence \r\n");
        *pos = 1;
        return NULL;            /* all data is displayed in one chunk */
    } else if (cur_array_num == 2) {
//printk("seq_next invoked in second sequence, entry num = %d \r\n", *((int *)entry_num));
        if (*((int *)entry_num) < MAX_CONFIG_ENTRIES2)
        {
            (*(int *)entry_num)++;
            return entry_num;
        } else
            return NULL;
    }
    return NULL;
}
static void proc_test_config_stop(struct seq_file *m, void *entry_num)
{
    if (*((int *)m->private) == 1)
    {
//printk("seq_stop invoked in first sequence \r\n");
        return;
    } else if (*((int *)m->private) == 2) {
//printk("seq_stop invoked in second sequence");
        seq_printf(m, "\n\n ");
        return;
    }
}
static int proc_test_config_read(struct seq_file *m, void *entry_num)
{
    int cur_array_num=*((int *)m->private);
//printk("seq_show invoked in sequence %d \r\n", cur_array_num);
    if (cur_array_num == 1)
    {
//printk("seq_show invoked in first sequence \r\n");
        seq_printf(m, "\n%s \n\n%s \n\n", proc_test_config_buff,
                proc_test_config_buff_format);
    } else if (cur_array_num == 2) {
//printk("seq_show invoked in second sequence \r\n");
        if (*((int*)entry_num) < MAX_CONFIG_ENTRIES2)
            seq_printf(m, "%d ", proc_test_config_buff2[*((int *)entry_num)]);
    }
    return 0;
}

  • Writing APIs: Here is some sample code that helps provide inputs to the kernel module through procfs (writing to kernel module). This code uses seq_file interface. I will cover details of this interface in another blog post.

static int proc_test_config_open(struct inode *, struct file *);
static ssize_t proc_test_config_write(struct file *,
        const char __user *, size_t , loff_t *);
static struct file_operations proc_test_config_file_ops = {
        .owner = THIS_MODULE,
        .open = proc_test_config_open,
        .read = seq_read,
        .write = proc_test_config_write,
        .llseek = seq_lseek,
        .release = seq_release,
};
static ssize_t proc_test_config_write(struct file *file,
        const char __user *buffer, size_t size, loff_t *ppos)
{
    char *buff, *buff1, **end_ptr = NULL;
    unsigned int i;
    if (size > CONFIG_BUFF_MAX_SIZE)
        return 0;
    copy_from_user(proc_test_config_buff_tmp, buffer, size);
    proc_test_config_buff_tmp[size] = '\0';
    buff = proc_test_config_buff_tmp;
    for (i=0; i< MAX_CONFIG_ENTRIES; i++)
    {
        buff1 = buff;
        while (isdigit(*buff))
                buff++;
        if (*buff != '\n') {
                if (*buff == ' ')
                        buff++;
                else
                        return 0;
        }
        switch (i) {
            case 1:
                use_hash_tbl_tmp = simple_strtoul(buff1, end_ptr, 10);
                break;
            case 2:
                max_hash_tbl_size_tmp = simple_strtoul(buff1, end_ptr, 10);
                break;
            case 3:
                log_stats_tmp = simple_strtoul(buff1, end_ptr, 10);
                break;
            case 4:
                max_stats_tmp = simple_strtoul(buff1, end_ptr, 10);
                break;
        }
    }
    *buff = '\0'; /* Ignoring any additional input user may have provided */
    /* Copy to the real config buffer & variables */
    strcpy(proc_test_config_buff, proc_test_config_buff_tmp);
    use_hash_tbl = use_hash_tbl_tmp;
    max_hash_tbl_size = max_hash_tbl_size_tmp;
    log_stats = log_stats_tmp;
    max_stats = max_stats_tmp;
    return size;
}

  • How to remove a proc file?
remove_proc_entry(PROC_TEST_CONFIG, proc_test_dir);

  • How to remove a proc directory?
remove_proc_entry(PROC_TEST_DIR, NULL);


Example kernel module illustrating procfs file creation:
https://github.com/babuneelam/procfsv2_seq


procfs read/write outputs for the example kernel module:
root@babu-VirtualBox:~/examples/proc/procv2_seq# ls
err           modules.order     proc_test.c    proc_test.mod.c        proc_test.mod.o
Makefile  Module.symvers  proc_test.ko  proc_test.mod.gcno  proc_test.o
root@babu-VirtualBox:~/examples/proc/procv2_seq#
root@babu-VirtualBox:~/examples/proc/procv2_seq# ls /proc | grep test
root@babu-VirtualBox:~/examples/proc/procv2_seq# insmod proc_test.ko
root@babu-VirtualBox:~/examples/proc/procv2_seq# ls /proc | grep test
test
root@babu-VirtualBox:~/examples/proc/procv2_seq# cd /proc/test
root@babu-VirtualBox:/proc/test# ls
config
root@babu-VirtualBox:/proc/test# cat config
Config 1 Info:
----------------------------
0 0 0 0 
Format:
          whether data sould be stored in a hash table
           Max Hash table size
           whether to log statistics
          Max number of statistics to be stored
   
Config 2 Info:
----------------------------
20 21 22 23 24 25
root@babu-VirtualBox:/proc/test# 
root@babu-VirtualBox:/proc/test# echo "1 0 1 0" > config
root@babu-VirtualBox:/proc/test# cat config
Config 1 Info:
----------------------------
1 0 1 0

Format:
          whether data sould be stored in a hash table
           Max Hash table size
           whether to log statistics
          Max number of statistics to be stored 
Config 2 Info:
----------------------------
20 21 22 23 24 25
root@babu-VirtualBox:/proc/test#

Wednesday, September 10, 2014

Creating and Applying a Patch File


Recently, I went over the patch file creation & application process in linux. In this post, I will cover a few linux commands useful for creating a patch file & applying a patch file.


Creating a Patch File

Sometimes, we need to create a patch file & distribute it to customers, partners, etc.

To create a patch, we need a copy of original source code directory & the modified source code directory. Lets say we are starting to modify the sources at /home/babu/patch_tests//valgrind_tests. Before any modifications, its better to take a copy to /home/babu/patch_tests//valgrind_tests_new & then modify the sources in /home/babu/patch_tests//valgrind_tests_new.

Now, to create the patch file, execute this command:
diff –Naur    <old_dir>  <new_dir>      >   file.patch
Example: 

babu@babu-VirtualBox:~/patch_tests$ diff -Naur valgrind_tests valgrind_tests_new > vg.patch
babu@babu-VirtualBox:~/patch_tests$ cat vg.patch
diff -Naur valgrind_tests/vg_test.c valgrind_tests_new/vg_test.c
--- valgrind_tests/vg_test.c        2014-09-10 21:26:39.473561882 -0700
+++ valgrind_tests_new/vg_test.c            2014-09-10 21:29:41.966273636 -0700
@@ -4,6 +4,12 @@

 int global_array[100] = {-1};
 +/* Testing patch functionality */
+void patch_test()
+{
+  return 1;
+}
+
  void
 unintialized_use()
 {
babu@babu-VirtualBox:~/patch_tests$
Now, remove the first line in the patch - which displays the command. After the removal the file should be like this:
babu@babu-VirtualBox:~/patch_tests$ cat vg.patch
valgrind_tests/vg_test.c        2014-09-10 21:26:39.473561882 -0700
+++
valgrind_tests_new/vg_test.c            2014-09-10 21:29:41.966273636 -0700
@@ -4,6 +4,12 @@

 int global_array[100] = {-1};
 +/* Testing patch functionality */
+void patch_test()
+{
+  return 1;
+}
+

  void
 unintialized_use()
 {
babu@babu-VirtualBox:~/patch_tests$


Applying the Patch File

Lets say we are receiving patch files & need to apply them.

Now, to apply the patch file, execute this command:
patch -p1 <source file> < <patch specific to source file>
Example:
For the earlier example I discussed above, I duplicated the unchanged sources to  /home/babu/patch_tests//valgrind_tests_patched. Now, to patch vg.patch to this duplicated sources, here is what I did:
babu@babu-VirtualBox:~/patch_tests$ patch -p1 valgrind_tests_patched/vg_test.c < vg.patch
patching file valgrind_tests_patched/vg_test.c
babu@babu-VirtualBox:~/patch_tests$ diff -Naur valgrind_tests valgrind_tests_patched/
diff -Naur valgrind_tests/vg_test.c valgrind_tests_patched/vg_test.c
--- valgrind_tests/vg_test.c   2014-09-10 21:26:39.473561882 -0700
+++ valgrind_tests_patched/vg_test.c         2014-09-10 21:49:07.039469608 -0700
@@ -4,6 +4,12 @@
 
int global_array[100] = {-1};
 +/* Testing patch functionality */
+void patch_test()
+{
+  return 1;
+}
+

void
unintialized_use()
{
babu@babu-VirtualBox:~/patch_tests$
I will try to cover patching of multiple files in a directory some other time.


Hope this helps.


Tuesday, September 9, 2014

VirtualBox Error - Kernel driver not installed


I have been VirtualBox in my macbook pro. But, I stopped using it in last 3-4 months. And when I tried to use it today again, it threw up the following errors:


Error in Virtual Box window:
Failed to open a session for the virtual machine MyUbuntu.
Virtual machine 'MyUbuntu' has terminated unexpectedly during startup. 

NS_ERROR_FAILURE (0x80004005)
Machine
IMachine {<<<some big number here>>>}

Error in an additional popup window:
Kernel driver not installed (rc=-1908)
Make sure the kernel module has been loaded successfully.


Instead of debugging how to fix this issue, I just updated the virtualbox with an available newer version (Virtual Box on top left --> Check for updates). 

After update the error went away. None of my existing VMs or config was impacted due to the upgrade.


Hope this helps.

Monday, June 16, 2014

Internet Browsing from pubilc computers - Safety & Privacy


At times, I had to access Internet from public computers in place such as libraries, non-profit organizations etc. My family in India accesses Internet primarily from public kiosks.  In this post, I will cover a few basic internet safety & privacy tips that can be helpful when accessing internet from such public computers.


Internet Safety & Privacy - Importance


Following are some harmful effects of using Internet without caution:
  • Identity theft
    • The recent security breach - Heartbleed - turned me extremely cynical about internet safety. 
While I am not going to offer solution here for complex security issues such as Heartbleed,  I will provide some basic guidelines to protect yourself from even simpler but potentially harmful internet security issues.
  • Privacy

According to me, it is utmost important to be cautious about safety & privacy of personal data while accessing internet from public computers.


Internet Safety & Privacy - Guidelines & How tos

I will cover 'how to's for IE 9 & Chrome Version 35. If my time permits, I will try adding 'how to's for other browsers as well. For other versions of IE & Chrome, the instructions may be more or less similar, but its best to search over internet for your specific browser versions, if different from IE 9 & Chrome v 35.

  • Before you begin your Internet browsing session
    • Choose proper Location: Ensure that you avoid exposing you computer monitor to public. That way, your personal information is not visible to accidental watchers.
    • Switch to Private Browsing: Most browsers support private browsing. If we operate in private browsing mode, the browsing history is not recorded in the local system. Any temporary files downloaded is not retained in the local system?
      • IE 9
        • Tools->Safety->InPrivate Browsing
      • Chrome v35
        • Chrome Menu ( Chrome menu ) --> New Incognito window
    • Disable Automatic Password Storage (or even prompting for such storage):
      • IE 9
        • Tools->Internet Options->Content->Auto Complete Settings : Uncheck the option "Usernames and password on forms"
      • Chrome v35
        • Chrome Menu ( Chrome menu ) -->Settings --> "Show Advanced Settings" --> "Passwords and Forms" section --> Uncheck the checkbox - " "
  • Before you end your Internet browsing session
    • Delete locally saved files - if you happen to save any files to desktop or other location during your browsing session.
    • Log out from any websites you logged in during your session
    • Delete temporary internet files & browsing history
      • IE 9
        • Tools->Safety->Delete Browsing history (check “Temporary Internet Files”)
      • Chrome v 35
        • Chrome Menu ( Chrome menu ) -->Tools --> Clear browsing data --> A dialog box opens: Select "beginning of the time" from drop down box, check all the check boxes --> Click "clear browsing data" 

Hope this helps.


Disclosure: 
I learnt some of the above high level ideas while volunteering as a credit coach at United Way Silicon Valley & also advised my coachees to follow these ideas.




    Friday, June 6, 2014

    ldd/objdump - finding shared library dependencies


    What is ldd?
    ldd stands for 'list dynamic dependencies'. It is a shell script that displays shared libraries required by a unix/linux program or a shared library.

    ldd internals

    Copy-pasted from http://linux.die.net/man/1/ldd :


    In the usual case, ldd invokes the standard dynamic linker with the LD_TRACE_LOADED_OBJECTS environment variable set to 1, which causes the linker to display the library dependencies. Be aware, however, that in some circumstances, some versions of ldd may attempt to obtain the dependency information by directly executing the program. Thus, you should never employ ldd on an untrusted executable, since this may result in the execution of arbitrary code. A safer alternative when dealing with untrusted executables is:

    $ objdump -p /path/to/program | grep NEEDED

    "

    LDD source code: http://stuff.mit.edu/afs/sipb/project/phone-project/bin/arm-linux-ldd
    (is this latest?)

    ldd command line options 
     
    babu@babu-VirtualBox:~$ ldd --help
    Usage: ldd [OPTION]... FILE...
          --help              print this help and exit
          --version           print version information and exit
      -d, --data-relocs       process data relocations
      -r, --function-relocs   process data and function relocations
      -u, --unused            print unused direct dependencies
      -v, --verbose           print all information
    For bug reporting instructions, please see:
    <https://bugs.launchpad.net/ubuntu/+source/eglibc/+bugs>.
    babu@babu-VirtualBox:~$ 

    Sample Usage

    Here are a few sample outputs:
    babu@babu-VirtualBox:~$ ldd /bin/lsmod
                linux-gate.so.1 =>  (0xb77ad000)
                libkmod.so.2 => /lib/i386-linux-gnu/libkmod.so.2 (0xb7765000)
                libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75b1000)
                /lib/ld-linux.so.2 (0xb77ae000)
    babu@babu-VirtualBox:~$ 

    babu@babu-VirtualBox:~$ ldd /lib/i386-linux-gnu/libc.so.6
                /lib/ld-linux.so.2 (0xb76e4000)
                linux-gate.so.1 =>  (0xb76e3000)
    babu@babu-VirtualBox:~$ 

    In the above outputs, the first field displays the shared library name & the second field (after ==>) displays the path of the shared library. In case the shared library is not found in the system, it displays "not found" in this field.

    Objdump way of finding dependencies
     
    babu@babu-VirtualBox:~$ objdump -p /bin/lsmod | grep NEEDED  
      NEEDED               libkmod.so.2
      NEEDED               libc.so.6
    babu@babu-VirtualBox:~$

    As we can see, objdump too is useful, but it misses out other details ldd displays. So, I prefer ldd over objdump to view shared library dependencies.

    References:

    Tuesday, May 20, 2014

    Toolchain basics


    Recently, I got an opportunity to explore toolchain basics. In this post, I will restrict my definitions/terms to C/Linux based development environment though toolchain term is used even in other development environments.

    What is a toolchain?

    A toolchain is used to build binaries for target system. In addition, toolchain helps in inspecting binaries, debugging, profiling  etc etc.

    What are the different components of a toolchain?

    • Mandatory:
      • GNU binutils: a set of development tools required to build and manage binaries - assembler, linker, strip, nm, objdump, readelf, ar, addr2line, gprof ..
      • Compiler: gcc
      • libc: glibc or eglibc or uClibc
    • Optional:
      • Debugger: gdb

    References:
    http://elinux.org/Toolchains
    UA-48797665-1