Search code examples
cpathenvironment-variablesstdoutstdio

My code gives out Environment variables on Linux


Some of this code might not make any sense, (perhaps even I am perplexed) about how this happened and why? This code was intended for some other purpose, (i was trying to make a calculator, so the main source code [which had few problems] exists on this site as my question) i somehow broke it and so i modified it and extracted the code which initially broke it.

I tested it on Kali Linux.

Here's the code:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

//Some of this might not make any sense, but its the way i was able to break it.. somehow
int main(int argc,char *argv[]) {
    FILE *file = fopen(argv[2],"a");
    if(file == NULL) {
        printf("Error Opening File!");
        return 1;
    }
    char ch;
    int i;
    printf("%i\n",argc);
    printf("%i\n",argv);
    while((ch = getopt(argc,argv,"d:"))!=EOF)
        switch(ch) {
        case 'd':
            for(i=4; i<=48; i++) // This loop may vary on other system. On first run i used "i<=51" , and on different system, same os, its the mentioned condition
                fprintf(file,"%s \n",argv[i]);
            fclose(file);
            break;
        default:
            fprintf(stderr,"No such command");
        }
    argc-=1;
    argv+=1;


    return 0;
}

The following result was produced upon running (the original source code. This code will write it to a file) :

value at argv= LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:.tar=01;31:.tgz=01;31:.arc=01;31:.arj=01;31:.taz=01;31:.lha=01;31:.lz4=01;31:.lzh=01;31:.lzma=01;31:.tlz=01;31:.txz=01;31:.tzo=01;31:.t7z=01;31:.zip=01;31:.z=01;31:.Z=01;31:.dz=01;31:.gz=01;31:.lrz=01;31:.lz=01;31:.lzo=01;31:.xz=01;31:.zst=01;31:.tzst=01;31:.bz2=01;31:.bz=01;31:.tbz=01;31:.tbz2=01;31:.tz=01;31:.deb=01;31:.rpm=01;31:.jar=01;31:.war=01;31:.ear=01;31:.sar=01;31:.rar=01;31:.alz=01;31:.ace=01;31:.zoo=01;31:.cpio=01;31:.7z=01;31:.rz=01;31:.cab=01;31:.wim=01;31:.swm=01;31:.dwm=01;31:.esd=01;31:.jpg=01;35:.jpeg=01;35:.mjpg=01;35:.mjpeg=01;35:.gif=01;35:.bmp=01;35:.pbm=01;35:.pgm=01;35:.ppm=01;35:.tga=01;35:.xbm=01;35:.xpm=01;35:.tif=01;35:.tiff=01;35:.png=01;35:.svg=01;35:.svgz=01;35:.mng=01;35:.pcx=01;35:.mov=01;35:.mpg=01;35:.mpeg=01;35:.m2v=01;35:.mkv=01;35:.webm=01;35:.ogm=01;35:.mp4=01;35:.m4v=01;35:.mp4v=01;35:.vob=01;35:.qt=01;35:.nuv=01;35:.wmv=01;35:.asf=01;35:.rm=01;35:.rmvb=01;35:.flc=01;35:.avi=01;35:.fli=01;35:.flv=01;35:.gl=01;35:.dl=01;35:.xcf=01;35:.xwd=01;35:.yuv=01;35:.cgm=01;35:.emf=01;35:.ogv=01;35:.ogx=01;35:.aac=00;36:.au=00;36:.flac=00;36:.m4a=00;36:.mid=00;36:.midi=00;36:.mka=00;36:.mp3=00;36:.mpc=00;36:.ogg=00;36:.ra=00;36:.wav=00;36:.oga=00;36:.opus=00;36:.spx=00;36:.xspf=00;36:

value at argv= XDG_MENU_PREFIX=gnome-

value at argv= LANG=en_IN

value at argv= GDM_LANG=en_IN

value at argv= MANAGERPID=793

value at argv= DISPLAY=:1

value at argv= INVOCATION_ID=3e7f771adfde4001af637f9527e9cc9d

value at argv= COLORTERM=truecolor

value at argv= USERNAME=root

value at argv= XDG_VTNR=2

value at argv= SSH_AUTH_SOCK=/run/user/0/keyring/ssh

value at argv= S_COLORS=auto

value at argv= XDG_SESSION_ID=3

value at argv= USER=root

value at argv= DESKTOP_SESSION=gnome

value at argv= PWD=/media/root/F89AF7139AF6CCDE

value at argv= HOME=/root

value at argv= JOURNAL_STREAM=9:19456

value at argv= SSH_AGENT_PID=945

value at argv= QT_ACCESSIBILITY=1

value at argv= XDG_SESSION_TYPE=x11

value at argv= XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/

value at argv= XDG_SESSION_DESKTOP=gnome

value at argv= DBUS_STARTER_ADDRESS=unix:path=/run/user/0/bus,guid=11c587e1337f9fb06858c2415bbac73a

value at argv= GTK_MODULES=gail:atk-bridge

value at argv= WINDOWPATH=2

value at argv= TERM=xterm-256color

value at argv= SHELL=/bin/bash

value at argv= VTE_VERSION=5002

value at argv= DBUS_STARTER_BUS_TYPE=session

value at argv= XDG_CURRENT_DESKTOP=GNOME

value at argv= GPG_AGENT_INFO=/run/user/0/gnupg/S.gpg-agent:0:1

value at argv= SHLVL=1

value at argv= XDG_SEAT=seat0

value at argv= LANGUAGE=en_IN:en

value at argv= WINDOWID=39845894

value at argv= GDMSESSION=gnome

value at argv= GNOME_DESKTOP_SESSION_ID=this-is-deprecated

value at argv= LOGNAME=root

value at argv= DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus,guid=11c587e1337f9fb06858c2415bbac73a

value at argv= XDG_RUNTIME_DIR=/run/user/0

value at argv= XAUTHORITY=/run/user/0/gdm/Xauthority

value at argv= PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

value at argv= SESSION_MANAGER=local/kali:@/tmp/.ICE-unix/894,unix/kali:/tmp/.ICE-unix/894

value at argv= _=./a.out

value at argv= (null)

My question that follows is, what actually are environment variables? And why did my give me such results?

// probably use one option at a time
//This code has some flaws, for example i didnt check if the file was opened 
or not, etc, pardon me for it. This is the actual un-edited source of the 
code.

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int add(int a,int b){
return a+b;
}

int subtract(int a, int b){
return a-b;
}

int main(int argc, char *argv[]){
FILE *file1 = fopen("Results.txt","a");
char ch;
int res;
while((ch=getopt(argc,argv,"a:s:"))!=EOF)
    switch (ch){
        case 'a':
            res = add(atoi(optarg),atoi(argv[3]));
            fprintf(file1,"%i\n",res);
            break;
        case 's':
            res = subtract(atoi(optarg),atoi(argv[3]));
            printf("%i \n",res);
            fprintf(file1,"%i\n",res);
            break;
        default:
            fprintf(stderr,"No such option");
            return 1;

    }
//THe commented out section produces weird behaviour...

//printf("Opind = %i, argc = %i, argv = %i \n",optind,argc,argv);

argc-=optind;

//printf("value at optarg = %i value at argv_3= %s \n",optarg,argv[3]);

argv+=optind;

//printf("Opind = %i, argc = %i, argv = %i \n",optind,argc,argv);

//printf("value at optarg = %i value at argv_3= %s \n",optarg,argv[1]);

fprintf(file1,"\nWritten to file\n");

fclose(file1);


return 0;
}   

Solution

  • First of all, going out of bounds of an array leads to undefined behavior. You probably do that when you iterate over the argv array without checking for e.g. i < argc (unless you actually provide over 48 arguments on the command line).

    Secondly, as for why you print the environment variables when going out of bounds of argv, it's because on POSIX systems (like Linux or macOS) there's a third argument to the main function, usually called environ. Similar to argv it's an array of strings (declared the same way, e.g. char *environ[]) that contains the environment variables. By going out of bounds of argv you go into the memory for the environ array.


    On a related note, you use argv[2] without any checking that the argument actually exists, or that it's not any other argument you parse with getopt. Don't do that.

    Also note that the getopt function returns an int. This is actually very significant and important for the check against -1 (not EOF!).