Linux Loadable Kernel Module to keep an eye on the system, and add security 'on the fly' to a prexisting running box. Contains a simple implementation of BSD securelevels, while waiting for the official 'in-distro' arrival of Linux Capabilities [POSIX 1.e] in 2.4.x and strong ACLs.
acb13ad23d34d3ac027d69404c713c283d541fe9f98969f2779ff97bcff33812
/*
* LuCe.c Linux Loadable Kernel Module to keep
* an eye on the system, and add security
* 'on the fly' to a prexisting running
* box. Contains a simple implementation
* of BSD securelevels, while waiting for
* the official 'in-distro' arrival of
* Linux Capabilities [POSIX 1.e] in 2.4.x
* and strong ACLs.
* For more infos, please check out the
* accompanying article on number 8 of
* BFi, the free e-zine, downloadable from
* this URL:
*
* ---[ http://www.s0ftpj.org/bfi/ ]---
*
* __NO__(C)2000 FuSyS [S0ftPj|BFi]
* <fusys@s0ftpj.org>
*
*
* Compil with: gcc -c -O2 -fomit-frame-pointer LuCe.c
* Install with: insmod LuCe.o <secure=level>
*
* 3l33t quote: "wow, and does it work on Solaris ?"
* Tnx'n'credits: 4.4BSD, Daemon9(Hardening the ...),
* Pragmatic(LKM paper), BFi
*
*/
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/dcache.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <sys/syscall.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/segment.h>
#define LKMNAME "LuCe"
#define DISK 6
volatile int secure=0;
MODULE_PARM(secure, "i");
char *protetti[10]={"/etc/passwd", "/etc/shadow", "/dev/mem", "/dev/kmem", NULL,
NULL, NULL, NULL, NULL, NULL};
struct inode luxes[10];
extern void *sys_call_table[];
int (*old_open)(const char*, int, mode_t);
int (*old_unlink)(const char*);
int (*old_ioctl) (unsigned int, unsigned int, unsigned long);
int (*old_umount)(char*, int);
int (*old_mount)(char*, char*, char*, unsigned long, void*);
int (*old_execve)(struct pt_regs);
int (*old_query_module)(const char *, int, char *, size_t, size_t *);
unsigned long (*old_create_module)(const char*, size_t);
int inocpy(struct inode * inode, struct inode *dest)
{
if (!dest) return -EFAULT;
memcpy(dest,inode,sizeof(struct inode));
return 0;
}
int inocmp(struct inode *in1, struct inode *in2)
{
if (kdev_t_to_nr(in1->i_dev)!=kdev_t_to_nr(in2->i_dev)) return 1;
if (in1->i_ino!=in2->i_ino) return 1;
return 0;
}
/* ~linux/fs/stat.c */
int do_revalidate(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
if(inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
/* ~linux/fs/namei.c */
struct dentry *kernelnamei(const char *name)
{
struct dentry *dentry;
dentry=lookup_dentry(name, NULL, 1);
if(!IS_ERR(dentry)){
if(!dentry->d_inode){
dput(dentry);
dentry = ERR_PTR(-ENOENT);
}
}
return dentry;
}
/* ~linux/fs/namei.c */
void get_lux_inode(const char *name, struct inode *inode)
{
struct dentry *dentry;
int error;
dentry = kernelnamei(name);
error=PTR_ERR(dentry);
if(!IS_ERR(dentry)){
error = do_revalidate(dentry);
if(!error) inocpy(dentry->d_inode, inode);
dput(dentry);
}
}
void get_luxes()
{
int i=0;
while(protetti[i] && i<10) {
get_lux_inode(protetti[i], &luxes[i]);
i++;
}
}
int lux_open(const char *filename, int flags, int mode)
{
int i=0;
struct inode lux;
char *name;
if(current->pid != 1 || current->p_opptr->pid != 1){
name=getname(filename);
get_lux_inode(name, &lux);
while(protetti[i]){
if(!inocmp(&lux, &luxes[i])){
if(flags & (O_RDWR|O_WRONLY)){
printk(KERN_INFO
"LuCe: Tentativo di Scrittura su %s mediante %s [UID %d TTY %s]\n",
filename, current->comm, current->uid,
current->tty->driver.driver_name);
putname(name);
return -EACCES;
}
}
i++;
}
if(secure) {
if((S_ISBLK(lux.i_mode))&&(lux.i_gid==DISK)){
if(flags & (O_RDWR|O_WRONLY)){
if(current->pid != 1 || current->p_opptr->pid != 1){
printk(KERN_INFO
"LuCe: Accesso Raw al disco %s mediante %s [UID %d TTY %s]\n",
filename, current->comm, current->uid,
current->tty->driver.driver_name);
putname(name);
return -EACCES;
}
}
}
}
}
return (*old_open)(filename, flags, mode);
}
int lux_unlink(const char *pathname)
{
int i=0;
struct inode lux;
char *name;
name=getname(pathname);
get_lux_inode(name, &lux);
while(protetti[i]){
if(!inocmp(&lux, &luxes[i])){
printk(KERN_INFO
"LuCe: Tentativo di Unlink su %s mediante %s [UID %d TTY %s]\n",
pathname, current->comm, current->uid, current->tty->driver.driver_name);
putname(name);
return -EACCES;
}
i++;
}
putname(name);
return (*old_unlink)(pathname);
}
int lux_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
unsigned int flags;
struct file *f;
if(cmd == EXT2_IOC_SETFLAGS){
f=current->files->fd[fd];
if(get_user(flags, (int *)arg)) return -EFAULT;
if(secure){
if(((flags&(EXT2_APPEND_FL|EXT2_IMMUTABLE_FL))^
(f->f_dentry->d_inode->u.ext2_i.i_flags&(EXT2_APPEND_FL|EXT2_IMMUTABLE_FL)))){
printk(KERN_INFO
"LuCe: Tentativo di Modifica %s su %s mediante %s [UID %d TTY %s]\n",
(flags&(EXT2_APPEND_FL))?"EXT2_APPEND_FL":"EXT2_IMMUTABLE_FL",
f->f_dentry->d_name.name, current->comm, current->uid,
current->tty->driver.driver_name);
return -EPERM;
}
else return (*old_ioctl)(fd, cmd, arg);
}
}
return (*old_ioctl)(fd, cmd, arg);
}
int lux_umount(char *name, int flags)
{
if(secure){
printk(KERN_INFO
"LuCe: Tentativo di Umount su %s [UID %d TTY %s]\n", name,
current->uid, current->tty->driver.driver_name);
return -EPERM;
}
return (*old_umount)(name, flags);
}
int lux_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
if(secure){
printk(KERN_INFO
"LuCe: Tentativo di Mount su %s [UID %d TTY %s]\n", dev_name,
current->uid, current->tty->driver.driver_name);
return -EPERM;
}
return (*old_mount)(dev_name, dir_name, type, new_flags, data);
}
int lux_execve(struct pt_regs regs)
{
char *filename;
char **argvs;
int error;
filename=getname((char *) regs.ebx);
argvs = (char **)regs.ecx;
error = PTR_ERR(filename);
if (IS_ERR(filename)) return error;
if(strstr(filename, "/sbin/init")){
if((strstr(argvs[1], "6"))||(strstr(argvs[1], "0"))){
printk(KERN_INFO "LuCe: Chiusura del Sistema\n");
secure = 0;
}
}
error = do_execve(filename,(char **)regs.ecx,(char **)regs.edx,®s);
if (error == 0) current->flags &= ~PF_DTRACE;
putname(filename);
return error;
}
void ttycredit(char *str)
{
struct tty_struct *mytty;
if((mytty = current->tty) != NULL) {
(*(mytty->driver).write)(mytty, 0, str, strlen(str));
}
}
unsigned long lux_create_module(const char *name, size_t size)
{
if(secure){
printk(KERN_INFO
"LuCe: Tentativo di Caricamento Modulo %s [UID %d TTY %s]\n",
name, current->uid, current->tty->driver.driver_name);
return -EPERM;
}
else return (*old_create_module)(name, size);
}
int new_query_module(const char *name, int which, char *buf, size_t bufsize,
size_t *ret)
{
int res, cnt, errno=0;
char *ptr, *match;
res = (*old_query_module)(name, which, buf, bufsize, ret);
if(res == -1)
return(-errno);
if(which != QM_MODULES)
return(res);
ptr = buf;
for(cnt = 0; cnt < *ret; cnt++) {
if(!strcmp(LKMNAME, ptr)) {
match = ptr;
while(*ptr)
ptr++;
ptr++;
memcpy(match, ptr, bufsize - (ptr - (char *)buf));
(*ret)--;
return(res);
}
while(*ptr)
ptr++;
ptr++;
}
return(res);
}
int init_module(void)
{
EXPORT_NO_SYMBOLS;
get_luxes();
old_open = sys_call_table[SYS_open];
sys_call_table[SYS_open] = (void *) lux_open;
old_unlink = sys_call_table[SYS_unlink];
sys_call_table[SYS_unlink] = (void *) lux_unlink;
old_ioctl = sys_call_table[SYS_ioctl];
sys_call_table[SYS_ioctl] = (void *) lux_ioctl;
old_umount = sys_call_table[SYS_umount];
sys_call_table[SYS_umount] = (void *) lux_umount;
old_mount = sys_call_table[SYS_mount];
sys_call_table[SYS_mount] = (void *) lux_mount;
old_execve = sys_call_table[SYS_execve];
sys_call_table[SYS_execve] = (void *) lux_execve;
old_create_module = sys_call_table[SYS_create_module];
sys_call_table[SYS_create_module] = (void *) lux_create_module;
old_query_module = sys_call_table[SYS_query_module];
sys_call_table[SYS_query_module]=(void *) new_query_module;
ttycredit("\n\033[1;32mLuCe \033[1;34m[Linux 2.2.x LKM] by FuSyS [S0ftPj|BFi]\033[0m\r\n\r\n");
printk(KERN_INFO "LuCe LKM Attivato\n");
return 0;
}
void cleanup_module(void)
{
sys_call_table[SYS_open] = old_open;
sys_call_table[SYS_unlink] = old_unlink;
sys_call_table[SYS_ioctl] = old_ioctl;
sys_call_table[SYS_umount] = old_umount;
sys_call_table[SYS_mount] = old_mount;
sys_call_table[SYS_execve] = old_execve;
sys_call_table[SYS_create_module] = old_create_module;
sys_call_table[SYS_query_module] = old_query_module;
ttycredit("\n\033[1;34mLuCe LKM Disattivato\033[0m\r\n\r\n");
printk(KERN_INFO "LuCe LKM Disattivato\n");
}