/* * LuCe.c Modulo Kernel per Linux per tenere * d'occhio il sistema, ed aggiungere * sicurezza 'al volo' ad un 'running' * preesistente. Contiene una semplice * implementazione dei securelevel BSD * in attesa dell'arrivo ufficiale con * le Linux Capabilities [POSIX 1.e] * nel kernel 2.4.x di solide ACL. * Per maggiori informazioni leggete * il relativo articolo sul numero 8 * di BFi, liberamente prelevabile e * consultabile dal seguente URL: * * ---[ http://www.s0ftpj.org/bfi/ ]--- * * __NO__(C)2000 FuSyS [S0ftPj|BFi] * * * * Compilate con: gcc -c -O2 -fomit-frame-pointer LuCe.c * Installate con: insmod LuCe.o * * 3l33t quote: "wow, e funzica anche su Solaris ?" * Tnx'n'credits: 4.4BSD, Daemon9(Hardening the ...), * Pragmatic(LKM paper), BFi * */ #define MODULE #define __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include #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"); }