Better alternatives?

I've heard people sAying that system(""); functions are not safe in terms of security and overall privacy of the program, could someone please explain this to me? And if so, what better alternatives would you suggest for functions like system("cls"),system("PAUSE") etc?
The 'better alternative' is to do it the way our OS is designed to do it.

For example, to clear the screen: http://www.cplusplus.com/articles/4z18T05o/

The *nixen way is to use the NCurses library. Fortunately, that's fairly cross-platform, since a Windows version exists as well (PDCurses).


However, the truly correct answer is:

Don't do that!


You really should not be playing with the console that way -- it isn't designed to work like that, and you really do cost your program power and flexibility.

I have previously described some of the important UI concepts in the following posts:
http://www.cplusplus.com/forum/beginner/1988/2/#msg10636 (controlling the user)
http://www.cplusplus.com/forum/beginner/1988/4/#msg14423 (streams vs tui applications)

Hope this helps.
A good alternative for
system("PAUSE") is
1
2
cin.get();
cin.get();
LOL, I suppose we can pick up right where we were in the other thread.
http://www.cplusplus.com/forum/beginner/1988/#msg7633

I still don't see how two gets are magically better than one. If the first one doesn't work for you, why not add another?

Don't <bleepity-bleep> do that!
Won's idea of two std::cin.get() caters to this particular situation:
the last input operation was a successful formatted input which was immediately followed by a single new-line.

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main()
{
    int a ;
    std::cout << "enter an integer immediately followed by a new-line."
                 "enter nothing more after the new-line\n" ;
    std::cin >> a ; // 

    std::cin.get(); // extract and throw away he new-line remaining in the input buffer
    std::cin.get(); // wait for the user to enter another new-line
}


while( std::cin.get() != '\n' ) ; // essentially std::ignore() for the first get is a little more robust; it too does not take care of: more than one new-line at the end, or stdin was redirected.
@Duoas

I get that you're against the very usage of clear and pause functions, but if one was to use them in their program, how would they go about it? I mean, why is it wrong to use system functions? I agree that the console may not "work" that way, but what is really going on here? I mean how do these system("") functions work?

Also, I checked out your linked thread, and someone mentioned something about creating a class with system("PAUSE"); in it's destructor, and that's great for programs that should stay open when the end is reached or some error is encountered but suppose:

1
2
3
4
5
6
7
8

cout; //some statements 
/** 
 code here to manipulate etc etc 
**/
cout<<\n Process Complete ";
/** Insert best pause statement here */
/*** Insert best clear screen statement here */ 


How would I go about this? Using curses and/or defining my own clearscreen() is possible and all, but this brings me to my second question; can we incorporate the source for those user defined pause/clear functions into existing header files itself? Along with their source code, and not only the #define ? If not (most probably not), why?

UPDATE - Read through the points abut applications not necessarily requiring a "human" infront of them, and yeah I get your point; but supppose my application was one that possessed a UI and required user inputs, then would it be viable to use system("")?

Also, what's the take on this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

 /* Standard error macro for reporting API errors */ 
 #define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %d from %s \ 
    on line %d\n", __FILE__, GetLastError(), api, __LINE__);}

 void cls( HANDLE hConsole )
 {
    COORD coordScreen = { 0, 0 };    /* here's where we'll home the
                                        cursor */ 
    BOOL bSuccess;
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 
    DWORD dwConSize;                 /* number of character cells in
                                        the current buffer */ 

    /* get the number of character cells in the current buffer */ 

    bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
    PERR( bSuccess, "GetConsoleScreenBufferInfo" );
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* fill the entire screen with blanks */ 

    bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
       dwConSize, coordScreen, &cCharsWritten );
    PERR( bSuccess, "FillConsoleOutputCharacter" );

    /* get the current text attribute */ 

    bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
    PERR( bSuccess, "ConsoleScreenBufferInfo" );

    /* now set the buffer's attributes accordingly */ 

    bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
       dwConSize, coordScreen, &cCharsWritten );
    PERR( bSuccess, "FillConsoleOutputAttribute" );

    /* put the cursor at (0, 0) */ 

    bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
    PERR( bSuccess, "SetConsoleCursorPosition" );
    return;
 }
 
Last edited on
@JLBorgs

This is good, but wouldn't the user have to press enter twice? And basically, I don't see how this is any different from getch(); or getche(); etc already defined in conio?
I just want to know if there is some way to have a robust, secure, console-friendly way to apply pauses and clearscreen, stuff that can actually be incorporated into final applications..
@JLBorges
I still haven't forgotten how it all works. And I know why the user adds two gets(). I'm complaining about the big hole in thought that lead to putting the second one there.

@Pratik K
If you are writing a "human required" UI, then you don't need the "pause" stuff. User quits the program, then it ask him to Press ENTER just to be good and sure. It's especially obnoxious if the program puts an "are you sure?" prompt in there before quitting.

When you click the [X] on a windowed application, you don't expect the window to hang around so you can look at it until you click on it again.

That's the same thing a "pause" does to a TUI application: user selects "I definitely want to quit now" and the window (or the program, at least) should disappear.


If you are writing a streams application, there is never any good reason to make your user have to wander by the PC every now and then just so he can confirm that your program has ended so that his batch processes can continue.


A lot of this requires thinking about how your user interacts with a process. For example, my Sony Blu-ray player is fairly nice in a lot of ways, but it has some horrible programming issues. One of which goes like this:

/me presses Netflix button
/blu-ray says "Connecting to network..."
/blu-ray says "Success! Press button to continue"
/me says "I've already pressed a button to connect to the network, I expect you to connect to the network, 'success' is non-information, I only care if you could not connect to the network, why do I have to press button again to watch TV program -- just do what I already asked!"

Make sense? It's obnoxious. It's like turning the key in your car, only to have the car say "Hey, I've successfully started! Please turn the key in the ignition again to acknowledge this great accomplishment!"

Only in software do we put up with such nonsensical abuse from our devices.


I admit there is a bit of a grey area here when it comes to beginner's programs on the (unfamiliar) console in a windowed environment. While the disappearing console window is annoying, it is also correct.

/me feeling annoyed for reasons that have nothing to do with what is here on the forums.
Sorry.
> wouldn't the user have to press enter twice?

Not if there already is a new-line left in the input buffer.


> I don't see how this is any different from getch(); or getche(); etc already defined in conio?

<conio.h> is not a standard header. I may not be (usually is not) available with current C++ implementations.


> have a robust, secure, console-friendly way to apply pauses

See if this works on your implementation (it normally would).
(Note: press 'enter' to continue instead of press 'any key' to continue.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <limits>

void pause( const char* prompt = "press enter to continue..." )
{
    std::cin.clear() ;
    auto stmbuf = std::cin.rdbuf() ;
    const int nothing = std::char_traits<char>::eof() ;
    const std::streamsize everything_upto = std::numeric_limits<std::streamsize>::max() ;
    const char new_line = '\n' ;

    if( stmbuf->in_avail() || ( stmbuf->sungetc() != nothing && std::cin.get() != '\n' ) )
        std::cin.ignore( everything_upto, new_line ) ;

    std::cout << prompt ;
    std::cin.ignore( everything_upto, new_line ) ;
}



> clearscreen

Clear the screen and leave the cursor at the bottom: crude, but effective:
void clear_screen( int nlines = 100 ) { for( int i = 0 ; i < nlines ; ++i ) std::cout << '\n' ; }

Clear the screen and leave the cursor at the top left: AFAIK, there is no standard C++ way to do this.

That doesn't work.

lenghty process
cat walks over keyboard, press <Return>
lenghty process ends
pause() doesn't pause
Last edited on
> See if this works on your implementation

>> That doesn't work. lengthy process. cat etc.

It is not guaranteed to work even if it was not a program that demands user interaction in a situation where the presence of an interactive user is unlikely, and there was no sprightly feline traipsing all over the keyboard.

Tip: buffering input is a good idea; in general, even in the aforementioned program, give the user a choice.
At the prompt for the first input, type in <input> <newline> <next_input> <new_line> <new_line> to let the program proceed - cat or no cat - to its logical conclusion without having to baby-sit the running program.
I haven't had a chance to play with it, but JLBorges's solution looks to be the most promising one I have ever seen using only Standard C++.

Pausing is inherently an OS-dependent + terminal-dependent kind of thing to do.
JLBorges's solution seems good, and I will definitely try it out
Thanks all; I am trying to make an offline social network of sorts and really hope some time soon, I'll be able to release a version that is not only stable, but secure as well. This is of the main reasons why I wanted to find a solution to the flaws of system("");

Basic use of these pause functions is when a user enters a message or something and on second thought decides not to send it in the first place. So it is then when he needs a secondary confirmation depending on whether his message is sent or not and then requires a keypress to proceed, rather go back to the main menu, so as to prevent unnecessary display of sensitive data.

Another question I have, as seen from the posts you linked, is why is it advisable not to define functions in header files itself? And rather to write the definitions in a header file and the functions themselves in a separate *.cpp file? This brings me to yet another question; what are MakeFiles? Are they, well, ironically, hard to make?

(ps - sorry for all these questions, I'm just really inquisitive, and want to make sure I'm following good programming etiquette)
@OP: As far as security goes; using the "system()" function is not what people mean when they say that it is insecure. Linking to libc is what causes the security issue. The "system()" function is simply what is most often targeted by a return to libc attack since it can call any executable that the parent process could and the child process will by convention inherit the security token from its parent. This problem is tempered somewhat by the adoption of the "principle of least privilege" among all of the major operating systems, but there will always be scenarios where it can't be avoided completely. Some processes go as far as hooking the "system()" function at run-time so that it does nothing but take a c-string and return null for the layer of security that it adds. But if you're actively using it within your application then obviously that isn't an option.

EDIT: I've done a bit more thinking and when people say that system is insecure they are probably referring the fact that it doesn't give you any means of control or monitoring over the child process. So this makes image hijacking simpler. It's only one component in an exploit chain, but it's one that can be easily avoided.
Last edited on
So basically, you mean to say that the user permissions and privileges can be "inherited" and programs can run as, say, admin, without actually having admin permission?
With an unsanitised command string (originating from a tainted source; say user input) or unsanitised environment strings, calling system() may result in exploitable vulnerabilities. Particularly so if it is called with elevated privileges.

The "return to lib-c attack" is a "buffer overflow exploit". It is not related to vulnerabilities that may be present because of a careless call to the system() function. See https://en.wikipedia.org/wiki/Return-to-libc_attack

Mitigation against this kind of vulnerability (buffer overflow attacks) is present in every current mainstream operating system. Open BSD, Windows, OS X and Android have particularly strong ASLR implementations.
https://en.wikipedia.org/wiki/Address_space_layout_randomization

Because of this, linking with libc is no longer considered to be a vulnerability.
JLBorges wrote:
... linking with libc is no longer considered to be a vulnerability.

Can I just say that I'm glad that someone else posted this. I felt for certain that I would have started an argument for some reason if it had been me.

@ OP:
... and programs can run as, say, admin, without actually having admin permission?

No, and it's kind of an important thing to note. At this point in the exploit, the "hack" has converged with the intended behavior of the operating system. Unless told otherwise, a child process is supposed to inherit its parent's token.

I think I get it now, thanks for clarifying. Basically, as all of you were saying from the start, if your application doesn't involve much user interaction, then system() functions can be exploited, by linking with libc, which however isn't a vulnerability anymore?
However, with the applications involving user interaction, which doesn't necessarily invoke or call other applications, and runs more or less within its own console, using system() functions wouldn't be so dangerous?
> then system() functions can be exploited, by linking with libc,

The vulnerability related to the call to system() is unrelated to the "return to lib-c vulnerability".

The "return to lib-c attack" is based on exploiting a buffer overflow on the stack to perform arc-injection.

system() is required to execute the command in a separate process in a separate address space.

The two are unrelated.

Linking with libc was ever a vulnerability only in a program which had a buffer overflow vulnerability in the first place - say, because of a call to the (now obsolete) gets() function. The ASLR mitigation against the "return to lib-c exploit" is effective for a program that does not run for a very long time, even if it has a buffer overflow vulnerability.

Mitigation against an exploit because of a call to system() is: sanitise the command string, sanitise the environment strings and drop privileges before invoking system().

Mitigation against the "return to lib-c attack" is to write the code in such a way that there is no possibility of buffer overflows on the stack (for instance, use std::string instead of c-style arrays for input.)
Oh, I got it, thanks a ton guys!
Topic archived. No new replies allowed.