I want to code a function called "CSys::Printf" using LD_Preload, but I think it would not be so easy, as in C you can't have "::" in function name, that would be needed to match the original function name.
A piece of the code used to hook would be like this:
int CSys::Printf(const char *format, ...) {
void *handle;
char *error;
if (conprint == NULL) {
handle = dlopen("dedicated.so", RTLD_LAZY);
if (!handle) {
fputs(dlerror(), stderr);
exit(1);
}
conprint = (int (*)(const char *format, ...))dlsym(handle, "CSys::Printf");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(1);
}
printf("*HOOK CSys::Printf OK*");
}
Well, this should work at hooking any function except this case, where the compiler won't accept the "::" on function name.
What should I do?
Thanks!
Related
I'm trying to implement the ls command in C with a few parameters like -a, -l... or -la, but I'm having issues with the parsing, when I use the input I get Segmentation Fault, this is an example of the -a parameter:
int comparator(char *av) {
int i = 0;
if (my_strcmp((av[i]), "-a") == 0)
return 0;
else
return 1;
}
int my_ls_a(char *path) {
int comp = comparator(path);
DIR *pdirec = opendir(".");
struct dirent *direc;
direc = readdir(pdirec);
while (direc != NULL || comp == 0) {
my_printf("%s ", direc->d_name);
direc = readdir(pdirec);
}
if ((path = readdir(pdirec)) == NULL)
my_printf("\n");
if (pdirec == NULL)
return (84);
closedir(pdirec);
return (0);
}
And this is my main:
int main(int ac, char *av[]) {
if (ac == 1)
my_ls_a(av[0]);
return 0;
}
I already have all the #include in a .h by the way.
When I only use the main function it works but not when I add the parameter -a.
It's probably better to use getopt() for parameter parsing instead of writing your own parser.
You have undefined behavior in the function comparator in my_strcmp((av[i]), "-a") because av is defined as a char * so you are passing a character where my_strcmp probably expects a pointer.
You should compile with -Wall -Werror to avoid such silly mistakes.
It is unclear why you pass only a single argument to my_ls_a. You should pass both ac and the argument array av and iterate on the arguments to parse the options.
Hi Im new to Cunit tests and testing in general. I cant find a way to test this void functon. Wondering how to properly do it or how to refactor it.
Any tips on how to properly test void functions? Thanks.
void validate_arg(int argc, char *argv[], struct Statistics *stats) {
if (argc == 4 && strcmp(argv[2], "-G") == 0) {
FILE *file = fopen(argv[3], "w");
stop_prog(write_stats(file, stats), err1);
fclose(file);
}
free(stats);
}
The Cunit test I wrote but I cant assert anything since its a void and I cant test if my file to write was created since since it gets deallocated inside the if.
void test_validate_args_0(void) {
struct Stats *stats = malloc(sizeof(struct Stats));
char* argv[] = {"TEST", "dummy", "-G", NULL};
CU_ASSERT_EQUAL(validate_arg(4, argv, stats), 0);
free(stats);
}
My code uses Pam library for user authentication. When the there is a failure to login. I would need to print syslog message in a specific format, instead of the current syslog format in the function pam_vsyslog of libpam library.
I intend to write a new function that would write syslog in my required format.
Below are definitions : in file pam_ext.h
extern void PAM_FORMAT((printf, 3, 0)) PAM_NONNULL((3))
pam_kniwx_vsyslog (const pam_handle_t *pamh, int priority,
const char *fmt, va_list args);
extern void PAM_FORMAT((printf, 3, 4)) PAM_NONNULL((3))
pam_kniwx_syslog (const pam_handle_t *pamh, int priority, const char *fmt, ...);
Implementation: libpam/libpam/pam_syslog.c
pam_kniwx_vsyslog (const pam_handle_t *pamh, int priority,
const char *fmt, va_list args)
{
char *msgbuf2 = NULL;
int save_errno = errno;
errno = save_errno;
if (vasprintf (&msgbuf2, fmt, args) < 0)
{
syslog (LOG_AUTHPRIV|LOG_ERR, "vasprintf: %m");
_pam_drop (msgbuf1);
return;
}
errno = save_errno;
syslog (LOG_AUTHPRIV|priority, "%s", msgbuf2);
_pam_drop (msgbuf2);
}
void
pam_kniwx_syslog (const pam_handle_t *pamh, int priority,
const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
pam_kniwx_vsyslog (pamh, priority, fmt, args);
va_end (args);
}
In case of authentication failure I would like to invoke pam_kniwx_syslog from libpam/modules/pam_unix/support.c function :
pam_kniwx_syslog(pamh, LOG_NOTICE,
"authentication failure; "
"logname=%s uid=%d euid=%d "
tty=%s ruser=%s rhost=%s "
"%s%s",
new->name, new->uid, new->euid,
tty ? (const char *)tty : "",
ruser ? (const char *)ruser : "",
rhost ? (const char *)rhost : "",
new->user && new->user[0] != '\0')
? " user=" : "",
new->user
);
With this change When I compile the code, I seem to run into undefined reference in spite having the definitions and the header file inclusion.
/usr/src/debug/libpam/1.3.0-r5/libpam-1.3.0/modules/pam_unix/../../../../../../../../libpam/modules/pam_unix/support.c:850: undefined reference to `pam_kniwx_syslog'
collect2: error: ld returned 1 exit status
Makefile:799: recipe for target 'pam_unix.la' failed
make[3]: *** [pam_unix.la] Error 1
make[3]: Leaving directory
Any help to resolve the issue is much appreciated.
The function definition provided in the source for redisAsyncCommand( ) is:
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { ... }
What is the purpose of the void *privdata argument? In what cases would it be useful?
As I understand by reading the code on gihub, the purpose of privdata is to send your callback some predefined data (which can be anything; that is why void* is used). In your callback (fn pointer to redisCallbackFn) you will recieve that privdata as parameter (for example look at cb->fn(ac,reply,cb->privdata); in func __redisRunCallback file async.c)
For example (simplified pseudo code for something similar) is bellow. In this example there are 3 successive calls to __redisAsyncCommandSimplified and only one handler (callback). In callback I have used privdata to determine behavior of
callback. Your callback can also use that privdata data for something else (like parameter for another function call, logging, structure creation/population, etc)...
#include <stdio.h>
#include <string.h>
typedef void (*Callback)(int, void*);
int __redisAsyncCommandSimplified(Callback call, void* privdata) {
call(1, privdata);
return 1;
}
void myHandler(int status, void* privdata) {
char* str = (char*)privdata;
printf("%s = ", str);
if (strcmp (str, "john") == 0) {
printf("lennon");
}
else if (strcmp(str, "ringo") == 0) {
printf("star");
}
else if (strcmp(str, "ringo") == 0) {
printf("star");
}
else if (strcmp(str, "paul") == 0) {
printf("mccartney");
}
else if (strcmp(str, "george")) {
printf("harrison");
}
else {
printf("who?!?");
}
printf("\n");
}
int main()
{
char c[20];
strcpy(c, "john");
__redisAsyncCommandSimplified(myHandler, c);
strcpy(c, "paul");
__redisAsyncCommandSimplified(myHandler, c);
strcpy(c, "someone else");
__redisAsyncCommandSimplified(myHandler, c);
return 0;
}
I'm trying to call execv after manually saerching for the program to execute.
In my case,
c is a struct which has args as an array of strings having the arguments passed while receiving input. nargs is the number of arguments.
c->args[0] would contain "ls","cat" etc.
I tried printing the value of the args[0], fullPath etc. in my child process. They all show values like "/bin/ls","/bin/cat" etc. But when I call execv, it returns -1 with an errno of 2, which I understand is the error for "No such file or directory". But I'm sure the file is there because thats what my PathResolver is returning after checking all permissions.
Can anyone point where I might have made a mistake.
//The part happening inside child
char *fullPath = PathResolver(c->args[0],1,&permission);
printf("FullPath: %s -- Permission: %d\n",fullPath,permission);
if(permission==0)
{
fprintf(stderr, "%s: Command not found\n",c->args[0]);
}
else if(permission==-1)
{
fprintf(stderr, "%s: Permission denied\n",c->args[0]);
}
else
{
char* args[c->nargs+1];
int m=0;
for(m=0;m<c->nargs;m++)
{
strcpy(args[m],c->args[m]);
}
args[c->nargs] = NULL;
printf("%d\n",execv(args[0], args));
printf("errno: %d\n",errno);
}
PathResolver function
char* PathResolver(char *command, int ResolverMode, int *Permission)
{
*Permission = 0;
char *returnString;
returnString = malloc((sizeof(char)));
char *strPath = getenv("PATH");
char *del = ":";
char *strToken = strtok(strPath,del);
FILE *f;
while(strToken)
{
char filePath[100];
sprintf(filePath,"%s/%s",strToken,command);
if(access(filePath,F_OK)>=0)
{
if(access(filePath,X_OK)>=0)
{
*Permission = 1;
sprintf(returnString,"%s%s ",returnString,filePath);
if(ResolverMode == 1)
break;
}
else
{
*Permission = -1;
}
}
strToken = strtok(NULL,del);
}
sprintf(returnString,"%s\b",returnString);
return returnString;
}
strcpy(args[m],c->args[m]); is undefined behaviour, because args[m] is not a pointer to valid memory.
The following might be simpler:
char * args[c->nargs + 1];
for (size_t m = 0; m != c->nargs; ++m)
{
args[m] = c->args[m];
}
args[c->nargs] = NULL;
There's no need to copy the strings.
(This may not be your actual problem, but it certainly prevents your program from being correct.)
execv() expects the program name to be prefixed by a full path as 1st parameter.
To have PATH searched instead of providing a path use execvp().
Update:
Also this line
returnString = malloc((sizeof(char)));
does only allocate 1 byte to returnString, which is way to few for how you use returnString.