Correct inline assembly code for sys_uname - c

I have written inline assembly code for the system call sys_uname, but it doesn't seem to be correct.
#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscalls.h>
#include <string.h>
struct utsname stroj;
__asm__ volatile("pushl $0;"
"pushl %%ebx;"
"pushl $0;"
"int $0x80;"
:
: "a" (SYS_uname), "b" (&stroj)
);
//uname(&stroj); -> when I do this it works, but again, I want to use inline assembly
write(1, stroj.nodename, strlen(stroj.nodename)); // 1 = stdout
Is there some glaring problem that I am not addressing? This write prints out nothing, literally "".

This answer assumes there is a reason why you wish to use system calls directly rather than through C library functions.
A version of the inline assembly that would be correct could look like:
#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <string.h>
#include <unistd.h>
/* SYS_uname has the value 164 */
/* #define SYS_uname 164 */
#define SYS_uname SYS_freebsd4_uname
int main()
{
u_int syscallnum = SYS_uname;
struct utsname stroj;
asm("push %[stroj]\n\t"
"push %%eax\n\t" /* Required dummy value for int 0x80 */
"int $0x80\n\t"
"add $8, %%esp" /* 2*4 bytes removed from stack */
: "+a"(syscallnum) /* error code also returned in syscallnum */
: [stroj]"r"(&stroj)
: "memory");
write(1, stroj.nodename, strlen(stroj.nodename));
return 0;
}
With FreeBSD 32-bit system calls the parameters are pushed on the stack in reverse order. A dummy value (any value) has to be pushed on the stack before issuing int $0x80. You need to adjust the stack pointer ESP after the system call. Any registers that may change need to be dealt with as well. int $0x80 will return an error code in EAX. The code above returns that value back in the syscallnum variable. If you modify a register in inline assembly and don't let GCC know it can cause undefined behaviour that is often hard to hunt down.
If you pass addresses via registers you will need to add memory operands (even if they are dummies) to specify that the data at the pointer in the registers is being read and/or written to. Alternatively you can specify the memory clobber which may be easier to understand although is a more brute force approach.
GCC's inline assembly is powerful but difficult to get right and can cause unexpected behaviour if you get it wrong. You should only use inline assembly as a last resort. FreeBSD has a syscall function that can be used to call most system calls.
You could have written the inline assembly above as:
asm(
"push %[stroj]\n\t"
"push %%eax\n\t" /* Required dummy value for int 0x80 */
"int $0x80\n\t"
"add $8, %%esp" /* 2*4 bytes removed from stack */
: "+a"(syscallnum), /* error code also returned in syscallnum */
"=m"(stroj)
: [stroj]"r"(&stroj));
FreeBSD 2+ doesn't support obsolete SYS_uname
If you try to run the code above you will discover it doesn't return anything. If you use the program TRUSS with a command like truss ./progname you should see something like this in the output:
obs_uname(0xffffc6f8,0x0,0x0,0x0,0x0,0x0) ERR#78 'Function not implemented'
This is because FreeBSD 2+ doesn't support the SYS_uname system call and is now considered obsolete. FreeBSD's libc uname makes calls to SYS___sysctl to populate the fields of the utsname structure. From the command line you can query the nodename using:
sysctl kern.hostname
You can call sysctl through a system call this way:
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#define OSNAME_MAX_LEN 256
/* SYS___sysctl has the value 202 */
/* #define SYS___sysctl 202 */
int main(void)
{
char osname[OSNAME_MAX_LEN];
size_t osnamelen = sizeof(osname) - 1;
int name[] = {CTL_KERN, KERN_HOSTNAME};
u_int namelen = sizeof(name) / sizeof(name[0]);
char * old = osname;
size_t * oldlenp = &osnamelen;
u_int syscallnum = SYS___sysctl;
asm("push %[newlen]\n\t"
"push %[new]\n\t"
"push %[oldlenp]\n\t"
"push %[old]\n\t"
"push %[namelen]\n\t"
"push %[name]\n\t"
"push %%eax\n\t" /* Required dummy value */
"int $0x80\n\t"
"add $28, %%esp" /* 7*4=28 bytes to remove from stack */
: "+a"(syscallnum) /* error code also returned in syscallnum */
: [name]"r"(name), [namelen]"r"(namelen),
[old]"r"(old) , [oldlenp]"r"(oldlenp),
[new]"i"(NULL), [newlen]"i"(0)
: "memory");
if (syscallnum) {
return EXIT_FAILURE;
}
osname[osnamelen]='\0'; /* Ensure the OS Name is Null terminated */
printf("This machine's node name is %s\n", osname);
return EXIT_SUCCESS;
}
When inline assembly adjusts ESP (push etc) it can cause memory operands generated by GCC and passed via a constraint to point at the wrong memory locations. This is especially true if any of the data is placed on the stack. To avoid this problem it is easiest to pass the addresses via registers.
Using the syscall function rather than inline assembly it could have also been written this way:
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#define OSNAME_MAX_LEN 256
/* SYS___sysctl has the value 202 */
/* #define SYS___sysctl 202 */
int main(void)
{
char osname[OSNAME_MAX_LEN];
size_t osnamelen = sizeof(osname) - 1;
int name[] = {CTL_KERN, KERN_HOSTNAME};
u_int namelen = sizeof(name) / sizeof(name[0]);
char * old = osname;
size_t * oldlenp = &osnamelen;
if (syscall(SYS___sysctl, name, namelen, old, oldlenp, NULL, 0) == -1) {
perror("sysctl");
return EXIT_FAILURE;
}
osname[osnamelen]='\0'; /* Ensure the OS Name is Null terminated */
printf("This machine's node name is %s\n", osname);
return EXIT_SUCCESS;
}

Related

Linux reboot system call returns error despite correct arguments

I am trying to power off my machine using the raw reboot system call. Here is my code:
#include <unistd.h>
#include <linux/reboot.h>
#include <stdio.h>
#include <errno.h>
int main(void) {
int ret = reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
if (ret == -1) {
printf("error: %d\n", errno);
}
return 0;
}
According to the man page, "Only the superuser may call reboot()". So I run the program as root and get the following output:
alex#laptop:~/code$ sudo ./a.out
[sudo] password for alex:
error: 22
What is error #22? That would be EINVAL, which according to the reboot man page signifies "Bad magic numbers or cmd". As I'm using the definitions provided by #include <linux/reboot.h>, I can't imagine the values are incorrect, but just in case, I also tried hardcoding the magic number values provided in the man page, to no avail (same error).
However, if I try glibc's wrapper function reboot(LINUX_REBOOT_CMD_POWER_OFF) provided by <sys/reboot.h>, it works fine (instantly shuts down machine).
There's no practical reason why I want to do this, just playing with syscall's and trying to make it work. If it helps, here are some details about the system I'm running this on:
Operating System: Ubuntu 20.04
Kernel: Linux version 5.4.0-53-generic
Compiler: gcc version 9.3.0
Let me know if any additional information might be useful!
I got this code from this link : Reboot with and without glibc
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#ifdef NO_GLIBC
#include <linux/reboot.h>
#else
#include <sys/reboot.h>
#endif
#ifdef NO_GLIBC
#ifndef LINUX_REBOOT_MAGIC1
#define LINUX_REBOOT_MAGIC1 0xfee1dead
#endif
#ifndef LINUX_REBOOT_MAGIC2
#define LINUX_REBOOT_MAGIC2 0x28121969
#endif
#ifndef LINUX_REBOOT_MAGIC2A
#define LINUX_REBOOT_MAGIC2A 0x05121996
#endif
#ifndef LINUX_REBOOT_MAGIC2B
#define LINUX_REBOOT_MAGIC2B 0x16041998
#endif
#ifndef LINUX_REBOOT_MAGIC2C
#define LINUX_REBOOT_MAGIC2C 0x20112000
#endif
#endif /* NO_GLIBC */
#ifndef LINUX_REBOOT_CMD_RESTART
#define LINUX_REBOOT_CMD_RESTART 0x1234567
#endif
#ifndef LINUX_REBOOT_CMD_HALT
#define LINUX_REBOOT_CMD_HALT 0xcdef0123
#endif
#ifndef LINUX_REBOOT_CMD_POWER_OFF
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
#endif
#ifndef LINUX_REBOOT_CMD_RESTART2
#define LINUX_REBOOT_CMD_RESTART2 0xa1b3c3d4
#endif
#ifndef LINUX_REBOOT_CMD_CAD_ON
#define LINUX_REBOOT_CMD_CAD_ON 0x89abcdef
#endif
#ifndef LINUX_REBOOT_CMD_CAD_OFF
#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
#endif
static void do_reboot(int command);
int
main(int argc, char *argv[]) {
int reboot_command;
if(argc == 1) {
fprintf(stderr, "No command given.\n");
fprintf(stderr, "Commands: RESTART, HALT, POWER_OFF, CAD_ON,
CAD_OFF.\n");
return(2);
} else if(strcasecmp(argv[1], "RESTART") == 0) {
reboot_command = LINUX_REBOOT_CMD_RESTART;
} else if(strcasecmp(argv[1], "HALT") == 0) {
reboot_command = LINUX_REBOOT_CMD_HALT;
} else if(strcasecmp(argv[1], "POWER_OFF") == 0) {
reboot_command = LINUX_REBOOT_CMD_POWER_OFF;
} else if(strcasecmp(argv[1], "RESTART2") == 0) {
fprintf(stderr, "RESTART2 not supported. Try RESTART.\n");
return(1);
} else if(strcasecmp(argv[1], "CAD_ON") == 0) {
reboot_command = LINUX_REBOOT_CMD_CAD_ON;
} else if(strcasecmp(argv[1], "CAD_OFF") == 0) {
reboot_command = LINUX_REBOOT_CMD_CAD_OFF;
} else {
fprintf(stderr, "%s not supported.\n", argv[1]);
fprintf(stderr, "Commands: RESTART, HALT, POWER_OFF, CAD_ON,
CAD_OFF.\n");
return(2);
}
do_reboot(reboot_command);
// Not reached, unless command was CAD_ON or CAD_OFF.
return(0);
}
static void
do_reboot(int cmd) {
int reboot_status = 0;
// Flush filesystem buffers before rebooting.
sync();
#ifdef NO_GLIBC
// Old libc.
reboot_status = reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd,
NULL);
#else
// glibc uses a wrapper around the system call.
reboot_status = reboot(cmd);
#endif
if(reboot_status == -1) {
if(errno == EPERM) {
fprintf(stderr, "Permission denied. Are you root?\n");
}
}
}
From this code, we can understand that the format for reboot in oldlibc is :
int reboot(int magic, int magic2, unsigned int cmd, void *arg);
and the format for reboot in glibc is : int reboot(int cmd);
Reason for Error 22: This error implies "Invalid argument" (EINVAL). glibc expects single argument in reboot(int cmd) function call ( glibc uses a wrapper around the system call), but we are giving multiple arguments. That's the reason for the error.
Please see the function call in the above code :
#ifdef NO_GLIBC
// Old libc.
reboot_status = reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd,
NULL);
#else
// glibc uses a wrapper around the system call.
reboot_status = reboot(cmd);
#endif
Although I was unable to make the int reboot(int magic, int magic2, int cmd, void *arg); syscall API work, I was eventually able to do this syscall using the lower level, general syscall API, like so:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
int main(void) {
syscall(169, 0xfee1dead, 672274793, 0x01234567);
return 0;
}
Magic numbers can be interpreted using the man page at man reboot.2. And here is the equivalent x86_64 assembly:
section .text
global _start
_start:
mov rax, 169
mov rdi, 0fee1deadh
mov rsi, 672274793
mov rdx, 001234567h
syscall
; The code below will never execute
mov rax, 60
mov rdi, 0
syscall
My original goal was to execute this syscall from assembly, so although I'm still curious why the reboot function wouldn't work, I'm satisfied with what I've got.
So it looks like actual values are needed.
As it states on the below man page, you want to use the magic numbers as follows;
reboot( (int) 0xfee1dead, 672274793, 0x4321fedc ); // For Power Off as you've expressed above
https://man7.org/linux/man-pages/man2/reboot.2.html

How do I make syscalls from my C program

How do I make system calls from my C program. For example, how do I call the following function? What headers would I have to include?
asmlinkage long sys_exit(int error_code);
You would normally call C library wrappers for the system calls (for example open() and read() are just wrappers). Wrappers are more friendly.
As an alternative to do the work yourself in assembly, you can try the syscall(2) function from glibc. This function makes a system call without a wrapper, and is specially useful when invoking a system call that has no wrapper function. In this manner you just need to provide symbolic constants for system call numbers, and also i think is more portable than coding the system call in assembler instructions.
Example from the doc:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
int
main(int argc, char *argv[])
{
pid_t tid;
tid = syscall(SYS_gettid);
tid = syscall(SYS_tgkill, getpid(), tid);
}
asm volatile(
"xorq %%rdi, %%rdi;" /* return value */
"movq $60, %%rax;" /* syscall id (/asm/unistd_64.h */
"syscall;"
::: "rdi", "rax"
);
You can't call it from pure C but you need to invoke it from assembly as would any wrapper like glibc.
Another way is using int 80h, but that's rather outdated.
In rdi you put error_code (0 in this case) while in rax the number which identifies the system call, available in /usr/include/asm/unistd.h that will in turn point you to the 32 or 64 bit version.
#define __NR_exit 60

MAC address using C

I am trying to write some C code which extracts the MAC no of a computer and prints it. Following is my code.
#ifndef WINVER
#define WINVER 0x0600
#endif
#include <stdlib.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <assert.h>
#pragma comment(lib, "IPHLPAPI.lib")
// BYTE has been typedefined as unsigned char
// DWORD has been typedefined as 32 bit unsigned long
static void PrintMACaddress(unsigned char MACData[])
{
printf("MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n",
MACData[0], MACData[1], MACData[2], MACData[3], MACData[4], MACData[5]);
}
// Fetches the MAC address and prints it
static void GetMACaddress(void){
IP_ADAPTER_ADDRESSES AdapterInfo[16]; // Allocate information for up to 16 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
// Arguments for GetAdapterAddresses:
DWORD dwStatus = GetAdaptersAddresses(0, 0, NULL, AdapterInfo, &dwBufLen);
// [out] buffer to receive data
// [in] size of receive data buffer
assert(dwStatus == ERROR_SUCCESS); // Verify return value is valid, no buffer overflow
PIP_ADAPTER_ADDRESSES pAdapterInfo = AdapterInfo; // Contains pointer to current adapter info
do {
PrintMACaddress(pAdapterInfo->Address); // Print MAC address
pAdapterInfo = pAdapterInfo->Next; // Progress through linked list
}while(pAdapterInfo); // Terminate if last adapter
}
int main(){
GetMACaddress();
return 0;
}
But when I run my code it gives the following error :
Error : undefined reference to `GetAdaptersAddresses#20'
All though the GetAdaptersAddresses() function is included in iphlpapi.h library.
I also tried running the code using the GetAdaptersInfo() function but also gives the same kind of error.
I am using CodeBlocks to compile my code using the GNU GCC C++ 98 compiler version.
The operating system which I am working on is Windows 7.
Can anybody point out the reason for this kind of error.
GCC does not support #pragma comment and there is no equivalent. You will need to update your project settings to specifically link with the Iphlpapi.lib library.

Reading/Writing errno or stack variable causes segfault. Why?

I have a really weird problem here, and haven't managed to find an answer online.
It appears after debugging with printf statements that a segfault ocurred when trying to read errno. Commenting problemed lines out one by one as they cause segfault resulted in having to comment out every reference to errno, after a readdir() call reaches the end of the directory stream and returns NULL.
Even then, the code then segfaults later when trying to access another automatic variable, file_count.
What is going on? Is this a stack overflow? How do I make it stop?
The code is below, if you feel the need to wade through it. All the problematic references to errno are removed, and the program segfaults after successfully executing the third second last line: printf("printing file_count\n");.
EDIT1: Here's a GDB backtrace:
#0 0xc95bf881 in strcpy () from /usr/lib/libc.so.1
#1 0x08051543 in dir_get_list (user=0x8047b88 "user1") at maildir.c:231
#2 0x08050f3e in main (argc=4, argv=0x80479f4) at maildir.c:43
END EDIT1
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#define MAX_FILENAME_LENGTH 255
#define MAX_USERNAME_LENGTH 40
#define MAX_PASSWORD_LENGTH 20
typedef int bool;
#define true 1
#define false 0
struct files_struct{
/*The number of email messages in a maildir.*/
int count;
/*A pointer to an array of pointers to the strings of the filenames. */
char **FileNames;
/*A pointer to an array of ints that give the corresponding size of the file.*/
int *FileSize;
};
typedef struct files_struct FilesStruct;
void dir_set_path(char* path);
bool check_user(char* username, char* pass);
FilesStruct* dir_get_list(char* user);
void delete_mail(char* user, char* filename);
char* get_file(char* user, char* filename);
FilesStruct* dir_get_list(char* user){
char maildir_name[MAX_FILENAME_LENGTH];
DIR * maildir_fd;
struct dirent *maildir_p;
strcpy(maildir_name,"./");
strncat(maildir_name,user,MAX_USERNAME_LENGTH);
strcat(maildir_name,"/");
if((pthread_mutex_lock(&maildir_root_mutex))<0)
perror("ERROR on locking maildir_root_mutex");
printf("Opening directory ""%s""\n",maildir_name);
if((maildir_fd = opendir(maildir_name))==NULL)
perror("ERROR on opendir");
int file_count = 0;
/* scan over entire directory, counting number of files to that data can be properly malloced */
while(1){
if((maildir_p = readdir(maildir_fd))==NULL){
closedir(maildir_fd);
printf("breaking loop\n");
break;
}
char file[MAX_FILENAME_LENGTH+1];
strcpy(file,maildir_p->d_name);
printf("File %d: '%s'\n",file_count+1,maildir_p->d_name);
/* if the file is a file other than an email */
if(!strcmp(".",file)||!strcmp("..",file)||!strcmp("pass",file)||!strcmp(".svn",file)){
printf("Continuing without incrementing file_count\n");
continue;
}
file_count++;
}
printf("%u\n",maildir_fd);
printf("printing file_count\n");
printf("%d",file_count);
printf("file_count printed successfully");
/* Additional code OMITTED */
I came across this recently. In my instance it was that another module had declared:
int errno = 0;
as a global, instead of #including errno.h. Any code that used the "proper" errno would immediately segfault.

Copying part of the stack and using mmap to map it to the current process

I want my program to do the following:
Open a new file.
Copy a (page-aligned) portion of the stack that includes the current frame pointer address to the file.
Map the contents of the file back into the process's address space in the same range as that of the original portion of the stack, so that the process will use the file for that part of its stack rather than the region of memory the system had originally allocated to it for the stack.
Below is my code. I am getting a segmentation fault on the call to mmap, specifically where mmap makes the system call with vsyscall. (I am working with gcc 4.4.3, glibc 2.11.1, under Ubuntu Server (x86-64). I have compiled and run both with 64-bit and 32-bit configurations, with the same results.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#define PAGE_SIZE 0x1000
#define FILENAME_LENGTH 0x10
#if defined ARCH && ARCH == 32
#define PAGE_SIZE_COMPLEMENT 0xfffff000
#define UINT uint32_t
#define INT int32_t
#define BP "ebp"
#define SP "esp"
#define X_FORMAT "%x"
#else
#define PAGE_SIZE_COMPLEMENT 0xfffffffffffff000
#define UINT uint64_t
#define INT int64_t
#define BP "rbp"
#define SP "rsp"
#define X_FORMAT "%lx"
#endif
#define PAGE_ROUND_UP(v) (((v) + PAGE_SIZE - 1) & PAGE_SIZE_COMPLEMENT)
#define PAGE_ROUND_DOWN(v) ((v) & PAGE_SIZE_COMPLEMENT)
UINT stack_low, stack_high, stack_length;
void find_stack_high(void) {
UINT bp = 0;
UINT raw_stack_high = 0;
/* Set the global stack high to the best
* approximation.
*/
asm volatile ("mov %%"BP", %0" : "=m"(bp));
while (bp) {
raw_stack_high = bp;
bp = *(UINT *)bp;
}
stack_high = PAGE_ROUND_UP(raw_stack_high);
}
int file_create(void) {
int fd;
char filename[FILENAME_LENGTH];
strcpy(filename, "tmp.XXXXXX");
fd = mkstemp(filename);
if (fd == -1) {
perror("file_create:mkstemp");
exit(EXIT_FAILURE);
}
unlink(filename);
return fd;
}
int main(void) {
int fd, bytes_written;
UINT bp;
off_t offset;
printf("In main\n");
fd = file_create();
printf("fd %d\n", fd);
find_stack_high();
// Get the current frame pointer.
asm volatile ("mov %%"BP", %0" : "=m" (bp));
// Store page boundary below
// frame pointer as end of potentially shared stack.
stack_low = PAGE_ROUND_DOWN(bp);
stack_length = stack_high - stack_low;
printf("start "X_FORMAT" end "X_FORMAT" length "X_FORMAT"\n",
stack_low, stack_high, stack_length);
bytes_written =
write(fd, (const void *)stack_low, PAGE_SIZE);
if (bytes_written != PAGE_SIZE) {
perror("main: write");
fprintf(stderr, "Num bytes: %x\n", bytes_written);
exit(EXIT_FAILURE);
}
offset = 0;
if (mmap((void *)stack_low, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED | MAP_GROWSDOWN, fd, offset) ==
MAP_FAILED) {
perror("file_copy: mmap");
exit(EXIT_FAILURE);
}
close(fd);
return EXIT_SUCCESS;
}
Thanks!
The stack changes (e.g. the return address for the mmap call) after you copied it. I can think of 2 possible ways around this:
Write asm that doesn't need the stack to perform the new mapping.
Call into a function with some huge local data so that the working stack is on a different page from the pages you're mapping over. Then, you could map over the lower addresses with a second call to mmap once this function returns.
Whatever you do, this is a horrible hack and probably a bad idea..
Tried turning on execute permission? In any case, the symptom suggests that you've managed to map in over the top of the stack, destroying the return pointer.

Resources