![]() |
C help
Background
We use SSHFS to dump images of our daughter (18 mo) to her website (my server). uid/guid ownership on the file is sshfs user:user and the uid www-data needs write access to the file so it can be converted/resized using Imagemagick. The below code runs suid (4770) with root:www-data and is called from a PHP script. The PHP code checks fileowner() on the image and if the owner is not www-data the below C code is called via system(). The data is sanitized in PHP prior to being passed to the suid binary, however, I want additional security measures in place. For example, no content will be outside of /www/dlf/dlf-albums. Here is an example argv[1] passed value: /www/dlf/dlf-albums/12-24 Months/Big Bubble bath 1.JPG Here is the PHP code snippet that calls the suid binary: Code:
//Fix file permissions if they are invalid, 33 is UID of www-data, fixperms is SUID 4770 root:www-dataI am not proficient in C by any stretch. I need the code modified to: 1) Check that argv[1] does not traverse outside of /var/www/dlf-albums 2) Use fprintf() instead of fputs() (isn't fputs less secure)? 3) For some reason asctime() is adding a newline character to the end of the string? 4) Be able to print output using something like fputs(fout,"%s\t%s\n",asctime(time(NULL)),argv[1]); without segfaulting :) 5) Create as secure code as possible. I certainly appreciate any help someone can give me. Again, C is not my strong point by any stretch. Code:
/* evilghost |
Re: C help
Quote:
Code:
if (argc != 2 || argv[1] == NULL2. Both will overflow if input string is not terminated. fsnprintf help a bit, but strings pointed by *argv are always terminated unless something is seriously broken. Always pass user-supplied string "through %s" (i.e. printf("%s", input); ), even when unnecessary. Sooner or later you forget to do it when it really counts. 3. The reason is described in the manual. :-) Use strftime if this bothers you. 4. Code:
char t[80];Maybe you could consider writing the log with syslog(3). |
Re: C help
This is good, thank you very much for your time/help.
|
Re: C help
This is what I ended up with, thanks again for your help, feel free to make any additional comments:
Code:
/* evilghost |
Re: C help
Quote:
- There is no reason for FILE *fout to be global. It's sufficient to have it only inside main-function. - Having an assignment, a function call, and a comparision in a single "if (foo)" is very C-ish. However in my opinnion this feature is often abused since complex statements easily become difficult to read. Code:
fout = fopen("foo", "a+");- It is perfectly safe (as far as printf can be) to have just fprintf(stderr, "Error while...\n");. When I said user input, I meant input from "unregulated" source such as command prompt, file, network, or such. A static string in source code is not user input. :-) - Similary to EXIT_FAILURE, most stdlib.hs come with EXIT_SUCCESS. - Since the executable is suid, I'd be extra careful to make sure target file is exactly what it's supposed to be (note that I don't know if uid/gid is set to something specific so that part may not apply): Code:
#include <sys/types.h> |
Re: C help
wnd, if you have the time to review the code again I'd certainly appreciate. I don't trust www touching a suid binary so I'm trying to create as much security as possible and you've been a huge help.
I read that using lstat() versus access() causes greater overhead and I should use access() in place with R_OK to test if the file is ready for reading (exists). I don't need to check uid/gid since they can be different values and I'm not too concerned about owner since they are dropped in by authenticated users (me or my wife) over SSH. I also added a input length check to ensure the path passed doesn't exceed 255 characters, a number I determined to be a reasonable input length. I also modified the code to take into account your suggestions. Code:
/* evilghost |
Re: C help
Quote:
What I do know is that access() happily follows symlinks. In other words you can create a symlink /www/dlf/dlf-albums/foo pointing at /bin and run your suid-executable to give wwwdata_GID (I hope that's a typo and it should read wwwdata_UID instead) full write access to /bin. As result, wwwdata_GID could potentially issue "rm -rf /bin" at his discretion. Quote:
Quote:
- wwwdata_GID is probably supposed to be wwwdata_UID. - If you end up using lstat, consider settings directories to 0770 and files to 0660. I'm also wondering is suid-executable is the right way in the first place. How about an inbox for the files and a cronjob to set the permissions and move the files into place? How about an sh-script that copies the files in place and sets the files 0660 and directories 0770? How about an sh-script that uploads the files for a cgi-script to process? (for file in $files; do wget --post-file $file https://intra/foo/import?file=foo%20bar/baz.jpeg; done) |
Re: C help
Thanks for your help, I've updated the code and I no longer get compiler warnings, everything looks good. I'm using stat now to check if it's a regular file to ensure symlinks aren't processed.
|
Re: C help
Quote:
|
Re: C help
I meant lstat, I used your code (thanks). I can repost what I'm using now if you want to take a look, I certainly appreciate your help.
|
Re: C help
I think there's very little left to comment but sure, I'll have a look if you paste it here once more. Email and IRC will also do. :-)
|
Re: C help
Code:
/* evilghost |
| All times are GMT -5. The time now is 05:12 AM. |
Powered by vBulletin® Version 3.7.1
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Copyright ©1998 - 2013, nV News.