Invoke execvp from linux driver - linux

Currently, i want to call execvp from kernel side.
My program is programmed to go to halt mode.
So i have tried to setup below code:
char *argv[] = { "/sbin/halt", "-f", NULL };
char * envp[] = {
"SHELL=/bin/sh",
"HOME=/",
"PATH=.:/sbin:/usr/sbin:/bin:/usr/bin",
"PWD=/",
NULL };
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
It seems that the code can execute halt command well.
But it does not meet the requirement about the electric signal.
I have checked, when i call execvp from the user space:
execvp ("halt", argv);
It worked well as expected.
I know that execvp will replace the current running programming by the new one specified in passing argument. When i use call_usermodehelper, that does not happen, i think it could be the difference.
Anyone know how can i solved this problem? How to make execvp work in driver similar to user space.
Thanks!

Related

Python3 read fron character device in blocking mode

I wrote a character device driver. Now I want to use python to read from it when there is data.
However, I found that the modules "io" as well as "os" do not block upon reading. The latter even when I set os.set_blocking(fd,true).
Is there a way to access the device in blocking mode?
Or do I miss something in the device driver (tail works fine)?
f=io.open("/dev/tstty0","r")
while (1)
data=str(f.read(32))
print("mark") # <--- endless list of marks
#do somthing
The read function of the device driver:
static ssize_t tstty_read(
struct file *filp,
char *buffer,
size_t length,
loff_t *offset)
{
unsigned char b;
unsigned long ofs=0;
devConfig* dev=filp->private_data;
if (dev)
{
while (fifoGet(&dev->tcp2dev,&b) && (ofs<length))
{
if (put_user(b,buffer+ofs))
{
printk(KERN_ERR "Could not copy user data");
return -EINVAL;
}
ofs++;
}
//printk(KERN_INFO "Reading device");
return ofs;
}
printk(KERN_ERR "Unknown device: %s",filp->f_path.dentry->d_iname);
return -EINVAL;
};
The read function reads any bytes available from a fifo. I none is available 0 is returned.
Kudos to Ian Abbott. A character device has to implement the ability to block a read request. The read file operation has to evaluate filp->f_flags & O_NONBLOCK to check if a client has requested blocking I/O.
This link helped me with an example:
simple linux driver code for blocking and non-blocking read
This example works but one has to consider two more things not covered in the example: a) What to do when you want to unload the driver while in read operation (just dont do it or wake up and abort)?
b) How to abort a client caught in blocking I/O?

What's the standard paradigm for exec'ing after dropping root?

In code like this in a daemon:
// run as root, after initgroups(...), setgid(...)
setuid(user);
const char* args[] = {"./userbinary",0};
execv("userbinary", args);
_exit(1);
there's an obvious problem where the user can attach to the process between the calls to setuid and exec[lvpe], and read out all the process's memory, including sensitive variables and state.
A workaround I use is like this (obviously, all error handling ommitted):
// run as root in daemon
const char* args = {"/usr/bin/mysetuid", uidStr, "./userbinary", 0};
execv("/usr/bin/mysetuid", args);
_exit(1);
// mysetuid.c:
int main(int arc, char* argv[]) {
setuid(atoi(argv[1]));
execv(argv[2], argv+2);
exit(1);
}
What is the "standard" way of doing this operation? Using a helper binary seems safest, but I can't find other applications that do this. For example, OpenSSH just relies on the fact that each user's connection gets its own process, so the setuid is always done from a process that has pretty much a blank slate.

Linux (Ubuntu) ioctl KDGETLED/KDGKBLED always 0

Code snippet below; basically, I am grabbing the active vt and issuing an ioctl KDGETLED against that terminal for the current state of the capslock/numlock/scrolllock keys and I always get result=0, regardless of the state of the lock keys.
I've tried this on multiple Linux boxes, all running variants of Ubuntu (e.g. Mint). I've tried other fds for the KDGETLED command such as "/dev/tty", "/dev/console", 0, etc. I'm running into the same problem with KDGKBLED. Are others experiencing the same issue, am I doing something silly, am I running into poorly written drivers, or something else?
int fd;
vt_stat stat;
fd = open("/dev/tty0", O_RDONLY);
if (ioctl(fd, VT_GETSTATE, &stat) == -1) {
fprintf(stderr, "Error on VT_GETSTATE\n");
exit(1);
}
close(fd);
char tty[128];
sprintf(tty, "/dev/tty%d", stat.v_active);
printf("Query tty: %s\n", tty);
char result;
fd = open(tty, O_RDWR | O_NDELAY, 0);
if (ioctl(fd, KDGETLED, &result) == -1) {
fprintf(stderr, "Error on KDGETLED\n");
exit(1);
}
close(fd);
printf("LED flag state: %d\n", result);
Thanks, in advance, to all who review my question.
Checkout the driver code, especially the struct file_operations instance for that driver, and check the function assigned to the .ioctl member - if that is poorly coded (I've seen a lot of shitty stuff happening in ioctls) then that is definitely your issue.
In this case I am pretty sure it is the drivers fault. As long the ioctl command shows no compile error, everything - especially error handling and input checking - is the task of the driver.

what does "__fortify_fail" do?

a user submitted a bug-report, where my application segfaults in "__fortify_fail()".
i understand that this is related to building my application with Debian's "hardening" flags -D_FORTIFY_SOURCE=2 -fstack-protector.
unfortunately the backtrace of the user does not tell me much yet, and the user is not super responsive (right now).
in order to understand better what is going on, i would like to know, what __fortify_fail actually does.
This function is normally just an error reporter. Sample code from glibc is:
extern char **__libc_argv attribute_hidden;
void
__attribute__ ((noreturn))
__fortify_fail (msg)
const char *msg;
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
libc_hidden_def (__fortify_fail)
It may be called here and there where sources is preferred to be fortified. "Fortification" itself is just a couple of run-time checks. Sample usage in openat function from io/openat.c is:
int
__openat_2 (fd, file, oflag)
int fd;
const char *file;
int oflag;
{
if (oflag & O_CREAT)
__fortify_fail ("invalid openat call: O_CREAT without mode");
return __openat (fd, file, oflag);
}
Without fortification, O_CREAT is acceptable without mode (still this case is highly suspicious, it is legal).
Think about __fortify_fail like about printf+abort.
Turning telepathy on about your question, I may suggest that user have some problems with using libc in user code. /lib/x86_64-linux-gnu/libc.so.6(+0xebdf0)[0x7f75d3576df0] is a place inside libc where some runtime-check fails, so pd[0x49b5c0] is a place where libc incorrectly called from.

/proc/devices still shows unregistered device

I am learning to write my first Linux char driver, but can't seem to make it work as expected.
The code for the driver module's init and exit functions are below:
static int __init one_init(void)
{
int result;
printk(KERN_DEBUG "In ones init call");
result = alloc_chrdev_region(&onedev, 0, 4, "one");
printk("Allocated device major: %d, first minor: %d",MAJOR(onedev),MINOR(onedev));
return 0;
}
static void __exit one_exit(void)
{
unregister_chrdev_region(onedev,4);
printk(KERN_DEBUG "In ones exit call");
}
My device still shows in /proc/devices after I unload my driver, whose exit function calls unregister_chrdev_region.
The dmesg command prints shows that my driver's init and exit calls were made.
I saw a few related questions, but the answers did not solve my seemingly simple problem.
What am I doing or expecting wrong?
Use 'rmmod modulename' in the terminal. This should unload the module and remove the associations.

Resources