13 Basic Linux System Calls Explained using a Fun Linux Virus Program

by Himanshu Arora on January 6, 2012

If you are interested in writing Linux system programming, you should learn all the basic library/system calls. This article has an example C program that covers a set of system calls that will help you understand the usage of these basic library calls.

The example C code given below does the following:

  • Automatically opens up some terminals
  • Displays the message that session is running as root or non-root
  • Display the above message on all the open terminals

The following are the 13 important library or system calls that are covered in the below example code.

  1. memset() : This function fills the first n bytes of the memory area pointed to by s with the constant byte c.
  2. fopen() : This function opens the file whose name is the string pointed to by its first argument and associates a stream with it.
  3. getcwd() : This function return a null-terminated string containing an absolute pathname that is the current working directory of the calling process
  4. getuid() : This function returns the real user ID of the calling process
  5. snprintf() : This function produces output according to a format and writes the output to a buffer.
  6. fwrite() : This function is used to write data to a stream
  7. fflush() : This function forces a write of all user space buffered data on to a particular stream
  8. fclose() : This function flushes the associated stream and closes the underlying file descriptor.
  9. system() : This function executes a command
  10. sleep() : This function makes the calling process sleep until specified seconds have elapsed or a signal arrives which is not ignored.
  11. opendir() : This function opens a directory stream
  12. readdir() : This function reads the directory which is opened as a stream
  13. atoi() : This function converts ascii argument to integer.

The following is the C code that shows how to use all of the above 13 system calls.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<dirent.h>
#include<sys/types.h>
#include<pwd.h>

// A buffer to hold current working directory
char cwd[512];

void inform(char *path, char *binary_name)
{
    // Declare variables for file operations
    FILE *fp = NULL;

    // A counter to be used in loop
    unsigned int counter = 0;

    // A buffer to hold the information message
    char msg[1024];
    // memset function initializes the bytes
    // in the buffer 'msg' with NULL characters
    memset(msg, '\0', sizeof(msg));

    memset(cwd, '\0', sizeof(cwd));

    // Check for the path to be non NULL
    if(NULL== path)
    {
         printf("\n NULL path detected\n");
         return;
    }

    // fopen will open the file represented
    // by 'path' in read write mode.
    fp = fopen(path,"r+");

    if(!fp)
    {
        printf("\n Failed to open %s\n",path);
        return;
    }
    else
    {
        printf("\n Successfully opened %s\n",path);
    }

    // getcwd() gives us the current working directory
    // of the environemt from which this binary was
    // executed
    if(NULL == getcwd(cwd,sizeof(cwd)))
    {
        printf("\n Failed to get current directory\n");
        return;
    }

    // getuid() returns the real user ID of the calling
    // process.
    // getuid() returns 0 for root and non zero for
    // any other user.
    if( 0 != getuid())
    {
        // This functions fills the buffer 'msg' with the formatted string by replacing %s in the harcoded string with the appropriate values
        snprintf(msg,sizeof(msg),"\n\n\nYOU ARE NOT ROOT!!!!!");
    }
    else
    {
       snprintf(msg, sizeof(msg),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nYOU ARE ROOT!!!!!!!!!!!!!!");
    }

   // Make sure the information8 is printed 25 times on each
   // open terminal
   for(counter=0;counter<25;counter++)
   {
       printf("\n fwrite()\n");
       // Write the information message on to the terminal
       fwrite(msg, strlen(msg), 1, fp);
       // Flush the message to the stdout of the terminal
       fflush(fp);
       // Wait for one second.
       sleep(1);
   }
   // close the file representing the terminal
   fclose(fp);

}

int main(int argc, char *argv[])
{
    // Since we will do some directory operations
    // So declare some variables for it.
    DIR *dp = NULL;
    struct dirent *ptr = NULL;

    // This variable will contain the path to
    // terminal
    char *path = NULL;

    // Used as a counter in loops
    int i =0;

    // Step1 :
    // Open 5 terminals each after 2 seconds
    // of delay.
    for(;i<5;i++)
    {
        // The system API executes a shell command
        // We try to execute two commands here
        // Both of these commands will open up
        // a terminal. We have used two commands
        // just in case one of them fails.
        system("gnome-terminal");
        system("/usr/bin/xterm");

        // This call is used to cause a delay in
        // program execution. The argument to this
        // function is the number of seconds for
        // which the delay is required
        sleep(2);
    }

    // Give user some 60 seconds before issuing
    // a information message.
    sleep(60);

    // Now, open the directory /dev/pts which
    // corresponds to the open command terminals.
    dp = opendir("/dev/pts");
    if(NULL == dp)
    {
        printf("\n Failed to open /dev/pts\n");
        return 0;
    }

    // Now iterate over each element in the
    // directory untill all the elements are
    // iterated upon.
    while ( NULL != (ptr = readdir(dp)) )
    {
        // ptr->d_name gives the current device
        // name or the terminal name as a device.
        // All the numeric names correspond to
        // open terminals.

        // To check the numeric values we use
        // atoi().
        // Function atoi() converts the ascii
        // value into integer

        switch(atoi(ptr->d_name))
        {
            // Initialize 'path' accordingly

            case 0:path = "/dev/pts/0";
                   break;
            case 1:
                   path = "/dev/pts/1";
                   break;
            case 2:
                   path = "/dev/pts/2";
                   break;
            case 3:
                   path = "/dev/pts/3";
                   break;
            case 4:
                   path = "/dev/pts/4";
                   break;
            case 5:
                   path = "/dev/pts/5";
                   break;
            case 6:
                   path = "/dev/pts/6";
                   break;
            case 7:
                   path = "/dev/pts/8";
                   break;
            case 9:
                   path = "/dev/pts/9";
                   break;
            default:
                   break;
         }
         if(path)
         {
             // Call this function to throw some information.
             // Pass the path to terminal where the information
             // is to be sent and the binary name of this
             // program
             inform(path, argv[0]);
             // Before next iteration, make path point to
             // NULL
             path = NULL;
         }

    }

    sleep(60);

    return 0;
}

The above code itself is self explanatory as it contains adequate comments that explains what those system calls does. If you are new to Linux system programming, this code gives enough exposure to the usage of all these important functions. For more details and advanced usage please read their man pages carefully.

This code is a simulation of a fun basic virus program. Once you compile and execute the above c program, it will do the following. This code was tested on Linux mint. But, it should work on all the ubuntu derivatives.

  • The user will see 5 terminals opening up one by one each after 1 second.
  • While the user will be wondering what just happened, all of his open terminals will slowly start getting repeated information about the login being root or non-root.
  • Please note that debug logging is enabled in the code for your learning purpose, please comment out the debug printf’s and then execute it if you want to have some fun.

Linux Sysadmin Course Linux provides several powerful administrative tools and utilities which will help you to manage your systems effectively. If you don’t know what these tools are and how to use them, you could be spending lot of time trying to perform even the basic administrative tasks. The focus of this course is to help you understand system administration tools, which will help you to become an effective Linux system administrator.
Get the Linux Sysadmin Course Now!

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

{ 2 comments… read them below or add one }

1 Biff Martin January 9, 2012 at 8:58 pm

Surely you have to be kidding us! There are no a “Fun Virus” codes anywhere. This may be more of an example of “annoyware” True virus code replicates itself by whatever means it is designed to do so. It may place a copy of itself on a boot sector of a removable drive, it may connect to a network port and copy itself to another host etc…

This little program only shows the usage of various system calls.

2 Anderson Ferreira August 28, 2012 at 11:07 am

Sorry, but these are not system calls, they are libc functions. Of course, some of them are wrappers to real syscalls, but not all.

Leave a Comment

Previous post:

Next post: