A second getpwuid call appears to overwrite old value - c

Here's a small C program that prints (well, supposed to print) the real and effective IDs of a process when the file has the setuid flag set. In this program, when I call getpwuid a second time (L.No 38), it tends to overwrite the value of the variable realUserName that was obtained in L.No 24. I'm unable to explain this behavior. Is this the expected behavior and why? I'm trying this in a Linux box (RHEL 2.6.18-371.1.2.el5).
1 /* Filename: test.c
2 * Notes:
3 * 1] ./test owned by user cadmn (userID: 3585)
4 * 2] ./test run by user pmn (4471)
5 * 3] ./test has the setuid bit switched-on.
6 */
7 #include <stdio.h>
8 #include <pwd.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 int main()
12 {
13
14 uid_t realId, effectiveId;
15 struct passwd *realUser, *effUser;
16
17 realId = getuid(); // realId = 4471
18 effectiveId = geteuid(); //effectiveId = 3585
19
20 printf("Real ID is %i and Effective ID is %i\n", (int)realId, (int)effectiveId);
21 //prints 4472 and 3585, respectively
22
23 realUser = getpwuid(realId);
24 char *realUserName = realUser->pw_name; //realUserName = pmn
25
26 printf("Real ID (name) at this point is %s\n", realUserName);
27 // prints pmn.
28
29 /*
30 *********************************************************
31 * *
32 * everything works as expected up to this point *
33 * *
34 *********************************************************
35 */
36
37 // The value obtained from this call is not used anywhere in this program
38 effUser = getpwuid(effectiveId);
39 printf("\nCalled getpwuid with the effectiveId\n\n");
40
41 printf("Real ID is %i and Effective ID is %i\n", (int)realId, (int)effectiveId);
42 //prints 4472 and 3585, respectively
43
44 printf("Real ID (name) at this point is %s.\n", realUserName);
45 // Expect to still see 'pmn' printed; though see 'cadmn' as the output!
46 // Why does this happen?
47
48 return 0;
49 }
50
Output:
pmn#rhel /tmp/temp > id pmn
uid=4471(pmn) gid=1000(nusers) groups=1000(nusers)
pmn#rhel /tmp/temp >
pmn#rhel /tmp/temp > id cadmn
uid=3585(cadmn) gid=401(cusers) groups=401(cusers)
pmn#rhel /tmp/temp >
pmn#rhel /tmp/temp > ls -l ./test
-r-sr-xr-x 1 cadmn cusers 9377 Dec 24 19:48 ./test
pmn#rhel /tmp/temp >
pmn#rhel /tmp/temp > ./test
Real ID is 4471 and Effective ID is 3585
Real ID (name) at this point is pmn
Called getpwuid with the effectiveId
Real ID is 4471 and Effective ID is 3585
Real ID (name) at this point is cadmn.
pmn#rhel /tmp/temp >

The behaviour you observe is the expected one.
The structure referenced by the return value of getpwuid() is defined statically internal to the latter, so it is expected to be filled (and with this overwritten) for each call to getpwuid().
This line
char * realUserName = realUser->pw_name;
just stores a reference to a value held by this statically internal structure. This value is also overwritten if the statically internal structure is overwritten by the next call to getpwuid().
To get around this there are two possibilities:
Use te reentrant version of getpwuid() which is getpwuid_r(). To be able to use it, add
#define _POSIX_SOURCE
before the very 1st #include statement in your program's sources.
Create copy of the members you need, pw_namein this case. The can be achieved by for example doing:
char * realUserName = strdup(realUser->pw_name);
Be awre that realUserName is now pointing to dynamically allocated memory, which needs to be free()ed by the program itself if not need anymore. To do so call
free(realUserName);

Related

First function in code executing, but code following the first function is not executed

My code executes the first function, but anything after the first function is not executed. I compiled using gcc -o -Wall and received no error messages.
when I tried to execute the code, I receive the execution at the bottom. I am not sure why the program will not execute more of the code. In the first function I can add more to the function to make work but it won't touch the other functions.
1 #include <stdio.h>
2 //functions prototypes
3 void compute_discount(void);
4 int print_results(void);
5
6
7 //defined Gloabal var
8 double Mdisc;
9 double Cost_of_purchase;
10 double DiscTot;
11 double Sales_tax;
12 double Total_price;
13 char military;
14
15 int main (void) {
16 //declare variables
17
18 //Cost of purchase
19 printf("Cost of purchase?\t\t$");
20 scanf ("%lf",&Cost_of_purchase);
21
22 //Military?
23 printf("In military (y or n)?\t\t\n");
24 scanf("%s",&military);
25
26 }
27
28
29 //function to compute discount
30 void compute_discount(void){
31
32 //compute military discount
33 switch(military){
34 case 'y':
35 case 'Y':
36 if(Cost_of_purchase > 150) {
37 Mdisc = .15 * Cost_of_purchase;
38 } else if (Cost_of_purchase < 150) {
39 Mdisc = .10 * Cost_of_purchase;
40 }
41 break;
42 case 'n':
43 case 'N':
44 Mdisc = 0;
45 break;
46 default:
47 printf("Error:bad input");
48 }
49
50 //cost minus military discount
51 DiscTot = Cost_of_purchase - Mdisc;
52 //sales tax
53 Sales_tax = .05 * DiscTot;
54 //Total Calculated
55 Total_price = DiscTot + Sales_tax;
56
57 printf("maybe this is the problem%f",Mdisc);
58 }
59
60 //function to print results
61 int print_results(void){
62
63 //if input is n N y Y then use below, this is not dependant on if military only if the letter is accepted
64 switch(military){
65 case 'y':
66 case 'Y':
67 case 'n':
68 case 'N':
69 printf("Military discount (15%%): \t\t$%f", Mdisc);
70 printf("Discounted total: \t\t$%f", DiscTot);
71 printf("Sales tax (5%%): \t\t$%f", Sales_tax);
72 printf("Total: \t\t$%f", Total_price);
73 break;
74 }
75 return(0);
76 }
Result of execution:
[p18d541#csci112 lab1]$ gcc -o lab1 -Wall lab1.c
[p18d541#csci112 lab1]$ ./lab1
Cost of purchase? $500
In military (y or n)?
y
[p18d541#csci112 lab1]$
I am wondering what more needs to be done to fix this issue, or what ways I can use to make the program execute those functions other than int main().
On this line:
scanf("%s",&military);
You're passing the address of a single char. While the %s format specifier expects a char * parameter which is what is being passed, it also expects it to point to the first byte of an array so that it may store a string. Because of this, the function attempts to write more than one byte when only one byte is available. Writing past the bounds of an object triggers undefined behavior.
This can be fixed by using the %c format specifier which is for reading a single char. You'll also need to add a space before it to consume the newline that the prior scanf left in the input buffer:
scanf(" %c",&military);
You also never called compute_discount and print_results, so you need to do that after reading the user's input.
int main (void)
{
printf("Cost of purchase?\t\t$");
scanf ("%lf",&Cost_of_purchase);
//Military?
printf("In military (y or n)?\t\t\n");
scanf(" %c",&military);
compute_discount();
print_results();
return 0;
}
You defined functions you want to use, but you are not calling these functions at all. Imagine a scenario, where you wanted to define a function to sum two numbers, int a and int b, and then call the function to count the sum. It would be:
int sum(int a, int b) {
return a + b;
}
int main() {
int a = 5;
int b = 10;
printf("result: %d\n", sum(a, b));
// ^^^^^^^^^
// call sum function
}
It means that after defining the function, you need to use it, so your main would be:
int main (void) {
printf("Cost of purchase?\t\t$");
scanf ("%lf",&Cost_of_purchase);
printf("In military (y or n)?\t\t\n");
scanf("%s",&military);
// Finally call your defined functions:
compute_discount();
print_results();
}
The other functions (besides main) are not executed because they are never called. main is called automatically when you run the program, but any other functions must be explicitly called. Add calls to compute_discount and print_results at the bottom of main, following the second scanf.
BTW, your second scanfis particularly dangerous, because you are using a "%s" format to read a single character... what happens if the user types in "yes"... where do the 'e' and the 's' go?

Stack Smashing Detected in GCC

I'm new to C and I've found a peculiar output from gcc that I'm having a hard time getting to the bottom of. The error upon running the application is:
*** stack smashing detected ***: /home/joshua/Research/cml/test terminated
Program received signal SIGABRT, Aborted.
0x00007ffff7a43428 in __GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
I've done some research on this, and it appears that this is many times caused by tying to put too large a value into an array, for example; I'm not doing anything like that.
Here is my sample code for reference:
1 #include <stdio.h>
2 #include <string.h>
3
4 struct student
5 {
6 int id;
7 char name[10];
8 float percentage;
9 };
10
11 int main()
12 {
13 int i;
14 struct student record[2];
15
16 // 1st student's record
17 record[0].id=1;
18 strcpy(record[0].name, "Raju");
19 record[0].percentage = 86.5;
20
21 // 2nd student's record
22 record[1].id=2;
23 strcpy(record[1].name, "Surendren");
24 record[1].percentage = 90.5;
25
26 // 3rd student's record
27 record[2].id=3;
28 strcpy(record[2].name, "Thiyagu");
29 record[2].percentage = 81.5;
30
31 for(i=0; i<3; i++)
32 {
33 printf(" Records of STUDENT : %d \n", i+1);
34 printf(" Id is: %d \n", record[i].id);
35 printf(" Name is: %s \n", record[i].name);
36 printf(" Percentage is: %f\n\n",record[i].percentage);
37 }
38 return 0;
39 }
The 2 in
struct student record[2];
is not the top index, it is the number of elements. And as you seem to know indexes start at zero which means the valid indexes are 0 and 1 for the above array. Going out of bounds leads to undefined behavior.
struct student record[2];
You've got an array of size 2 and you're trying to store 3 elements in it. Array indices go from 0 to n-1. record[2] is an invalid index.
To keep a check on the integrity of the functions, next to the return statement Gcc adds protection variables (called canaries) which have known values.In your case when the uninitialized access is done on record[2] you have violated the stacks integrity and the canary values are overwritten which trigger the crash.

Context switching - ucontext_t and makecontext()

I am studying context switching in C programming and have found the following example code on the Internet. I am trying to figure out whether only makecontext() function can trigger a function that does something. The other functions such as setcontext(), getcontext(), and swapcontext() are used for setting the context.
The makecontext() attaches a function and its parameter(s) to a context, does the function stick to the context all the time until a change is committed to it?
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ucontext.h>
4 #define MEM 64000
5
6 ucontext_t T1, T2, Main;
7 ucontext_t a;
8
9 int fn1()
10 {
11 printf("this is from 1\n");
12 setcontext(&Main);
13 }
14
15 void fn2()
16 {
17 printf("this is from 2\n");
18 setcontext(&a);
19 printf("finished 1\n");
20 }
21
22 void start()
23 {
24 getcontext(&a);
25 a.uc_link=0;
26 a.uc_stack.ss_sp=malloc(MEM);
27 a.uc_stack.ss_size=MEM;
28 a.uc_stack.ss_flags=0;
29 makecontext(&a, (void*)&fn1, 0);
30 }
31
32 int main(int argc, char *argv[])
33 {
34 start();
35 getcontext(&Main);
36 getcontext(&T1);
37 T1.uc_link=0;
38 T1.uc_stack.ss_sp=malloc(MEM);
39 T1.uc_stack.ss_size=MEM;
40 makecontext(&T1, (void*)&fn1, 0);
41 swapcontext(&Main, &T1);
42 getcontext(&T2);
43 T2.uc_link=0;
44 T2.uc_stack.ss_sp=malloc(MEM);
45 T2.uc_stack.ss_size=MEM;
46 T2.uc_stack.ss_flags=0;
47 makecontext(&T2, (void*)&fn2, 0);
48 swapcontext(&Main, &T2);
49 printf("completed\n");
50 exit(0);
51 }
makecontext writes the function info into a context, and it will remain there until it is overwritten by something else. getcontext overwites the entire context, so would overwrite any function written there by a previous call to makecontext. Likewise, swapcontext completely overwrites the context pointed at by its first argument.
The basic idea is that a u_context contains a snapshot of part of the process context at some time. It contains all the machine registers, stack info, and signal masks. It does NOT include any memory map or file descriptor state. The state in the u_context is precisely all the state you need to manipulate in order to implement threads or coroutines.
edit
swapcontext(&current, &another) saves the current context in current and switches to another. At some later point, the code (runnning from another context) may switch back to current (with another call to swapcontext) or it might switch to some third context.
When a context ends (the function set into it with makecontext returns), if some context is pointed at by its uc_link field, it will switch to that context. But if uc_link is NULL, then the thread (and process if there's only one thread) will exit -- other contexts that are not running will just be abandoned.

global variable is not incrementing properly

int count;
int main(){
count=0;
printf("%6d\t %6d\t %6d\t ",i+1,multiFib(i),count);
}
int multiFib(int x){
if (x<2){
return 1;
count++;
}}
In this code, count always gives 0 result. I made it a global variable, not to define it in the function again. How can I increase that variable?
It outputs in order; that is not problem. It gives the result:
1 1 0
-
2 1 0
-
3 2 0
So, count is not increasing — but why?
Although order of evaluation is not guaranteed (see multiple other answers), there is another, more fundamental problem (actually, two of them):
int multiFib(int x)
{
if (x<2){
return 1;
count++;
}
}
You attempt to increment count after you've returned from your function. Your compiler should be warning about unreachable code.
You don't return a value from multiFib() when the input is bigger than 2.
The fragment of main() that you show references an undefined variable i. I assume that is because you deleted a for (i = 0; i < 40; i++) loop from before the printf() statement. To fix the 'order of evaluation' problem, you might want to use:
int count;
int main(void)
{
for (int i = 0; i < 40; i++)
{
count = 0;
int fib = multiFib(i);
printf("%3d %10d %10d\n", i+1, fib, count);
}
return(0);
}
This evaluates the number of calls to multiFib() for each top-level call to the function.
For the multiFib() function itself, you probably need:
int multiFib(int x)
{
count++;
if (x < 2)
return x;
else
return multiFib(x-1) + multiFib(x-2);
}
Though this is an appallingly slow implementation of Fibonacci numbers so you shouldn't use this as an answer to your homework (but it does make a 'working' function).
Example output:
1 0 1
2 1 1
3 1 3
4 2 5
5 3 9
6 5 15
7 8 25
8 13 41
9 21 67
10 34 109
11 55 177
12 89 287
13 144 465
14 233 753
15 377 1219
16 610 1973
17 987 3193
18 1597 5167
19 2584 8361
20 4181 13529
21 6765 21891
22 10946 35421
23 17711 57313
24 28657 92735
25 46368 150049
26 75025 242785
27 121393 392835
28 196418 635621
29 317811 1028457
30 514229 1664079
31 832040 2692537
32 1346269 4356617
33 2178309 7049155
34 3524578 11405773
35 5702887 18454929
36 9227465 29860703
37 14930352 48315633
38 24157817 78176337
39 39088169 126491971
40 63245986 204668309
Note that if you go much beyond 40, you start getting arithmetic overflow. It also gets to be very (very, very) slow.
This:
if (x<2){
return 1;
count++;
}
You return from the function before you increment count. So it's never incremented.
Return doesn't just set the returned value. It actually exits the function at that point.
Just swap the order of those two lines. Also, you should keep an eye on your compiler warnings. Any decent compiler will warn you that the count++; line is unreachable.
printf("%6d\t %6d\t %6d\t ",i+1,multiFib(i),count);
The order of function argument evaluation is unspecified in C. multiFib can be evaluated before or after count in the printf function call.
The order of evaluation of function arguments is not specified.
In your code,
printf("%6d\t %6d\t %6d\t ",i+1,multiFib(i),count);
The argument to printf function multiFib(i) might be getting called after printing count.
Try this,
printf("%6d\t",multiFib(i));
printf("%6d\t %6d\t ",i+1,count);
to check the result.
As it was said in another answers, problem is that order of evaluation of function arguments is not specified, so in your example:
printf("%6d\t %6d\t %6d\t ",i+1,multiFib(i),count);
You can not be sure if count will be evaluated before or after passing multiFib(i) to the printf() function.
Please look here for more detailed information about evaluation order in C++, or here for evaluation order in C.
You might also find useful to force evaluation order by separating your printf into two calls:
printf("%6d\t",multiFib(i));
printf("%6d\t %6d\t ",i+1,count);
like Nishith Jain M R suggested in his answer.

Why can't I insert a breakpoint here (I might add all my friends can, and I see no other way to solve this)

(gdb) list 1,20
1 int swap_n_add(int *xp, int *yp)
2 {
3 int x = *xp;
4 int y = *yp;
5
6 *xp = y;
7 *yp = x;
8 return x + y;
9 }
10
11 int main() {
12 int a1 = 534;
13 int a2 = 1057;
14 int sum = swap_n_add(&a1, &a2);
15 int diff = a1 - a2;
16
17 return sum * diff;
18 }
(gdb) b 18
No line 18 in file "swap_n_add.c".
I want to check the value main returns, so I put a breakpoint at 18 to inspect the register there (info register). But it says that line doesn't exist, despite it... saying it does exist. And my friends with identical code can put it there.
I would question the previous setup steps that you haven't shown. If your friend's are able to set a breakpoint there and you are not, there is probably something you did wrong. (assuming everyone is using the same versions of all the tools)
with gdb version 7.4-2012.04 for Ubuntu and gcc 4.6.3 I can see and set a break point at the line in question:
> gcc -Wall -g file.c <-- compile with -g for debug symbols
> gdb a.out <-- run against the executable
This GDB was configured as "x86_64-linux-gnu". <-- make sure it was configured for
For bug reporting instructions, please see: your architecture
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/mike/C/a.out...done. <-- and that your file loads symbols
(gdb) line 22, 39
22 int swap_n_add(int *xp, int *yp) <-- mine are different because I have a bunch
23 { of #include's in my test file
24 int x = *xp;
25 int y = *yp;
26
27 *xp = y;
28 *yp = x;
29 return x + y;
30 }
31
32 int main() {
33 int a1 = 534;
34 int a2 = 1057;
35 int sum = swap_n_add(&a1, &a2);
36 int diff = a1 - a2;
37
38 return sum * diff;
39 }
(gdb) b 39
Breakpoint 1 at 0x400530: file file.c, line 39.
Note that if I pick a line outside of the file, say.. 75, it gives you a message about "no line x in file":
(gdb) b 75
No line 75 in the current file.
Make breakpoint pending on future shared library load? (y or [n])
If you're seeing this it's worth double checking your line numbers, it's possible you mis-counted.
If you want to see the value of the return (sum * diff) you can always set that to a local variable before returning and break on the return.
This may be compiler/debugger-specific. There may be no debug information generated for the closing brace.
Also, if you have optimization enabled, it can make it hard or impossible to put breakpoints at some locations. Try removing the -O parameter to gcc, if you use it.
If it still doesn't help, assign the return value to a new variable and return that variable instead.
Alternatively, you could just switch to the disassembly, put a breakpoint on the ret instruction of main() (the instruction that does function return on x86) and examine the returned value in the CPU registers (should be in eax on x86).

Resources