Is there some kind of security issue in this code? - c

This is my code:
void handle(int s)
{
char inbuf[4096];//we defined inbuf as 4096 size
dup2(s, 0);
dup2(s, 1);
setbuf(stdout, NULL);
alarm(ALARM_TIMEOUT_SEC);
printf("crackme> ");
if (NULL == fgets(inbuf, sizeof(inbuf), stdin)) {
return;
}
right_trim(inbuf);
if (is_correct(inbuf)) {
printf("Good job!\n");
}
}
And if there is, what is the problem?
Little explanation about this program:
The first part of her running Server
When someone connects to the server and enter an input (i did a loop to examine the length of the input)
So this function looks at it and if the pass is correct then its print "good job"

Answering the question as titled: yes. The use of
void setbuf(FILE *stream, char *buffer);
is deprecated due to security issues, and is retained by MSVC only for compatibility purposes. Please use
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);
which is more secure since the buffer size is also provided (as well as more flexibility by providing mode) and it returns a function value to indicate success or failure.

Related

How to get the hostname of mac os in C

I 'm trying to get the hostname of my school mac os. I can't use gethostname() as it's in section 3 of the man pages of my school macs, instead of section 2. Is there another way of getting the hostname, without using gethostname()? I'm only allowed to use libc functions in man 2 section.
gethostname is just a sysctl, and sysctl is just a syscall.
And syscalls are (per definition) in section 2 of the manual.
So grab your favourite disassembler (or otool -tV if you have none), nm the libraries in /usr/lib/system to find out which ones export _gethostname and _sysctl, and get to work (or look up the source :P).
Below I re-implemented gethostname using sysctl, and sysctl using syscall:
#include <sys/syscall.h> // SYS_sysctl
#include <sys/sysctl.h> // CTL_KERN, KERN_HOSTNAME
#include <unistd.h> // syscall
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
return syscall(SYS_sysctl, name, namelen, oldp, oldlenp, newp, newlen);
}
int gethostname(char *buf, size_t buflen)
{
int name[] = { CTL_KERN, KERN_HOSTNAME };
size_t namelen = 2;
return sysctl(name, namelen, buf, &buflen, NULL, 0);
}
int puts(const char *s)
{
// left as an exercise to the reader ;)
}
int main(void)
{
#define BUFSIZE 256
char buf[BUFSIZE];
size_t buflen = BUFSIZE;
if(gethostname(buf, buflen) == 0)
{
puts(buf);
}
return 0;
}
The implementation of sysctl isn't too complicated; you really just slap SYS_sysctl (from sys/syscall.h) in front of the other arguments and pass them all on to syscall.
To understand the implementation of gethostname, you have to know how sysctl works:
oldp is where the queried value will be stored.
newp is where the new value will be read from. Since we're not setting any new value, this is NULL here.
name is more or less the actual list of arguments to sysctl, and its contents depend on the actual sysctl being queried.
CTL_KERN denotes that we want something from the kernel.
KERN_HOSTNAME denotes that we'd like to retrieve the hostname.
And since KERN_HOSTNAME doesn't take any arguments, that's all there is to it.
Just for demonstration, had you called KERN_PROCARGS, name would require an additional argument, namely the process ID of which the arguments should be retrieved.
In that case, name would look like this:
int name[] = { CTL_KERN, KERN_PROCARGS, pid };
and namelen would have to be set to 3 accordingly.
Now in the above implementation I've made use of puts, which you're obviously not allowed to do, but I trust you can figure out how to re-implement strlen and use the write syscall with that. ;)

built in command to change prompt in custom linux/unix shell

I have looked all over google and I find how to change in the bash config files, but my project requires a built in command to change the prompt.
I declared char pointer outside any function, my command modifies it, but when the function returns (int to continue a do while loop) and the prompt is displayed again, it is blank.
I have tried using a structure, union, and even a second char pointer and got the same issue.
I thought using a global char pointer that could be accessed and modified in any function would be the solution to this part of my project.
I would appreciate and will try any response.
Edit:
posted on my phone, tried to ask w/o code, but here it is
Code:
char *prmpt;
...
int main(int argc, char **argv)
prmpt="$$ ";
do
{
printf("%s ", prmpt);
}while(1)
int cmd_prompt(char **args)
{
prmpt = (char*)args[1];
return 1;
}
Essentially one needs to use fgets or getline or better yet they might use readline or editline. Here is an example using getline:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *prompt;
size_t len = 256;
size_t i = 0;
if (!(prompt = malloc(256 * sizeof(char))))
return 1;
strcpy(prompt, "$");
while ( 1 )
{
printf("[[%s]] ", prompt);
i = getline(&prompt, &len, stdin);
prompt[i-1] = '\0';
}
}
Or if you might try implementing getline on your own using getchar ( perhaps if getline is not available on your system, or you just want to know how it works). And eventually move on to writing your own editline library if you continue to be interested in writing shells.

when use copy_to_user, it gives bad address

I am trying to add a proc file to read some information from kernel. But when I try to cat the information from the proc file, it gives "bad address" error.
int proc_read(char *buffer, char **starter, off_t off, int count,
int *eof, void *data)
{
if (off > 0)
{
*eof = 1;
return 0;
}
if (copy_to_user(buffer, info_str, info_str_size))
{
return -EFAULT;
}
return info_str_size;
}
After insmod, use cat to read the proc file, but gives the bad address error; info_str is a global char array.
The answer to your problem is surprisingly simple. In proc_read functions you don't need to use copy_to_user: a simple memcpy will do the job, since the buffer lives in kernel memory. If you're creating a proc_write function, however, you do need to use copy_from_user, since in this case the buffer lives in user memory.
One tip is that you should also probably signal EOF on success. This will save your function from needing to be called twice.
The following should suffice:
int proc_read(char *buffer, char **starter, off_t off, int count,
int *eof, void *data)
{
if (off > 0)
{
*eof = 1;
return 0;
}
memcpy(buffer, info_str, info_str_size);
*eof = 1;
return info_str_size;
}
You should also note that this way of writing file entries is pretty old and you should probably avoid it. The seq_file interface is much less error prone (and will work with pagers like less and more). Take a look at http://lwn.net/Articles/22355/ if you're interested.

Not null terminated string - a KlocWork error with no understandable reason

I've recently installed "klocwork" and am trying to get rid of bugs on an existing code.
The error shown seems to be simple. No null at the termination of the char * _p_.
I have manually added a null termination (even though there is no need), but it doesn't please the Klocwork. Any ideas?
The exact message is:-
Incorrectly terminated string 'p' causes a buffer overflow in p.
char *ptr;
int writtenchars = 0 ;
va_list args;
char* destStr;
if (argc != 2) {
printf(" wrong parameters number - %d instead of %d\n", argc, 2);
char str[25]="wrong parameters number ";
char *_p_; /********************************************************/
va_start(args, str);
destStr = (char*) malloc(SNMP_BUF_LEN);
_p_= destStr;
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in in function \"snmp_rebuildstringinbuf!!!\" \n");
destStr="kukuRiko";
}
else {
writtenchars = (int) vsnprintf(destStr, 4095, str, args);
if (writtenchars>SNMP_BUF_LEN) {
printf("WARNING: Too long string rebuilded in function \"snmp_rebuildstringinbuf!!!\" %d chars\n",writtenchars);
}
destStr[writtenchars] = '\0' ; //Moshe - making sure the last value of the string is null terminated in order to prevent future buffer overflows.
}
va_end(args);
/******************************************************************************/
//The KlocWork error relates to this line //
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
free (_p_);
===========================================================
Hi Guys,
Thanks for your answers, but it seems a bit more obscure than that. I have refined the code to this simple case:-
When the code is written all in one function there is no error, whereas, when the allocation section is wrapped in a function (and a text passed as parameter) the Klocwork error returns.
See this code:- version without an error:-
char *_p_; /*+++++++++++++++++++*/
int writtenchars = 0 ;
va_list args;
char* destStr;
char* str = "hello World";
va_start(args, str);
destStr = (char*)malloc(SNMP_BUF_LEN);
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in function \n");
}
else {
writtenchars = (int) vsnprintf(destStr, (SNMP_BUF_LEN) - 1, str, args);
}
/*+++++++++++++++++++*/
_p_ = destStr ;
if (_p_ != NULL) {
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
}
free (_p_);
/***********************************************************/
whereas when taking the code between /*++++ */ and wrapping it in a function returns the above KlocWork error.
Hence,
char *writingToSomeBuffer (char * str) {
int writtenchars = 0 ;
va_list args;
char* destStr;
va_start(args, str);
destStr = (char*)malloc(SNMP_BUF_LEN);
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in function \n");
}
else {
writtenchars = (int) vsnprintf(destStr, (SNMP_BUF_LEN) - 1, str, args);
}
return destStr;
}
int main () {
char *_p_;
_p_ = writingToSomeBuffer("hello world");
if (_p_ != NULL) {
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
}
free (_p_);
return 0 ;
}
any ideas?
KlocWork is correctly diagnosing the problem that you can be writing with a null pointer if memory allocation fails:
_p_= destStr;
if (destStr == NULL)
{
printf("WARNING: Failed to alloc memory in in function ...\n");
destStr = "kukuRiko";
At this point, the (horribly named) '_p_' variable is still null, but you go ahead and use it in the printing operation below.
Also note that the 'trivial' fix of adding '_p_' after this breaks your memory management; you later do 'free(_p_);' which will lead to horrible problems if '_p_' points to the constant string.
You also have 'memory in in function' in the message. And 'wrong parameters number' does mean roughly the same as 'wrong number of parameters' but the latter is more idiomatic English. I'm not convinced any of the exclamation marks are helpful in the error message; there is a strong argument that they should go outside the double quotes surrounding the function name even if one of them is deemed desirable.
With the revised version of the problem, I wonder if Klocwork is diagnosing what Microsoft says of its vsnprintf(), that it does not guarantee null termination (which is different from what C99 and POSIX says).
Jonathan has it right. We've recently broken up this checker into two families that might explain it better:
http://www.klocwork.com/products/documentation/Insight-9.1/Checkers:NNTS.MIGHT
http://www.klocwork.com/products/documentation/Insight-9.1/Checkers:NNTS.MUST
We are currently under development to clean this up and make it easier to understand. Not only the problem but the solution as well.
Klocwork's error aside, I think this code is wrong. Why are you limiting the vsnprintf to 4096, while the buffer size is SNMP_BUF_LEN? How do those two related to each other? If SNMP_BUF_LEN < 4096, then you may have just overflowed your buffer. Why wouldn't you pass SNMP_BUF_LEN as the limiting argument in vsnprintf?
Also, the write to destStr[writtenchars] is suspect. Depending on the variant of vsnprintf (they do vary), writtenchars might be the number of characters it wanted to write, which would again cause you to write past the end of your buffer.
That all said, Klocwork isn't perfect. We had macros that were very explicitly trying to be safe, and Klocwork mis-detected them as potentially overrunning the string. I think that was a snprintf case as well.
Overall a good product, but it does have a few holes and you can't fix all it's complaints.

C readline function

In an assignment for college it was suggested to use the C readline function in an exercise. I have searched for its reference but still haven't found it. Does it really exist? In which header? Can you please post the link to the reference?
Readline exists in two places, libreadline and libedit (also called libeditline). Both have an identical interface. The difference is libreadline is licensed under the GPL, libedit is 3 clause BSD. Licensing is really not a concern for an assignment, at least I don't think it is. Either license allows you to use the code freely. If you link against readline, be sure to make the whole program GPL 2 or later which will satisfy whatever version of the GPL governs the system readline. It may be GPL2+ or GPL3+, depending on the age of the system. I'm not advocating either license, that's up to you.
Note, take care to install either / or and adjust linking as needed (-lreadline or -ledit or -leditline). Both are libraries and not a part of the standard C library.
Edit (afterthought):
If releasing a program to the wild, its a nice gesture to allow the user to configure it with their readline of choice. For instance: --with-readline or --with-libedit, etc. This allows a binary package that conforms to their choice of license, at least as far as readline is concerned.
Links: Readline and Edit/Editline.
I don't think it's a standard function.
I simple implementation would be like this:
char *Readline(char *in) {
char *cptr;
if (cptr = fgets(in, MAX_LINE, stdin)) {
/* kill preceding whitespace but leave \n so we're guaranteed to have something
while(*cptr == ' ' || *cptr == '\t') {
cptr++;
}
return cptr;
} else {
return 0;
}
}
It uses fgets() to read up to MAX_LINE - 1 characters into the buffer 'in'. It strips preceding whitespace and returns a pointer to the first non-whitespace character.
Not sure if you tried reading this from the GNU C Library: ssize_t getline (char **lineptr, size_t *n, FILE *stream).
This function reads a line from a file and can even re-allocate more space if needed.
An example of this is found in the manpage of getline. Below is a copy of it.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
FILE *stream;
char *line = NULL;
size_t len = 0;
ssize_t nread;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
stream = fopen(argv[1], "r");
if (stream == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while ((nread = getline(&line, &len, stream)) != -1) {
printf("Retrieved line of length %zu:\n", nread);
fwrite(line, nread, 1, stdout);
}
free(line);
fclose(stream);
exit(EXIT_SUCCESS);
}
If you need a "readLine()" function, like the readLine() in Java-BufferedReader, you can also freely use my function «char* get_line(FILE *filePointer)» in "line.h", which I wrote just for this purpose: https://github.com/pheek/line.h/blob/master/line.h
It doesn't exist.
They were mistaken and referred to gets() from stdio.h.
Also this is a very unsafe function due to no maximum size to read parameter, making it immediate security whole (lookup buffer overrun attack). You may use fgets() instead.

Resources