全部博文(298)
分类: LINUX
2011-03-24 13:02:48
(8)设备访问控制之单用户访问
注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方
1.本文所介绍的程序平台
开发板:arm9-mini2440
虚拟机为:Red Hat Enterprise Linux 5
开发板上系统内核版本:linux-2.6.32.2
2.程序清单
本次实验程序为国嵌实验和tekkamanninja博客《LDD3》代码,本人作了改动和较为详细的注释,如有错误请指出。
注意:单用户访问控制有着这样的特点,首先root用户可以直接访问,其次就是其他用户如果是有阻塞的打开设备的话,设备会等到第一个打开设备的用户权限消失(也就是单用户的权限),之后阻塞消失继而让刚刚阻塞的用户继承了权限,以下的arm实验会证明这一点
uonly.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct cdev *singleUIDnb_cdev;
static int singleUIDnb_major = 0;
static int singleUIDnb_minor = 0;
module_param(singleUIDnb_major, int, S_IRUGO);
module_param(singleUIDnb_minor, int, S_IRUGO);
DECLARE_COMPLETION(comp);
/************************************************************************
*
* Next, the device with blocking-open based on uid
*/
static int singleUIDnb_count; /* 设置计数 initialized to 0 by default */
static uid_t singleUIDnb_owner; /* initialized to 0 by default */
static spinlock_t singleUIDnb_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(singleUIDnb_wait);
static inline int singleUIDnb_available(void)
{
return singleUIDnb_count == 0 ||
singleUIDnb_owner == current->cred->uid || /*允许用户*/
singleUIDnb_owner == current->cred->euid || /*允许执行su命令的用户*/
capable(CAP_DAC_OVERRIDE); /*root用户*/
}
static int singleUIDnb_open(struct inode *inode, struct file *filp)
{
spin_lock(&singleUIDnb_lock);
while (! singleUIDnb_available()) {
printk("<5> failed 1\n");//测试1 测试open失败后的情况
spin_unlock(&singleUIDnb_lock);
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
if (wait_event_interruptible (singleUIDnb_wait, singleUIDnb_available()))
return -ERESTARTSYS; /* tell the fs layer to handle it */
spin_lock(&singleUIDnb_lock);
printk("<5> failed 2\n");//测试2
}
if (singleUIDnb_count == 0)
//current->uid 可能只在低版本的内核才能用
//LINUX2.6.32.2 current->cred->uid
singleUIDnb_owner = current->cred->uid; /* grab it */
singleUIDnb_count++;
printk("<5> count : %d\n", singleUIDnb_count);
spin_unlock(&singleUIDnb_lock);
return 0; /* success */
}
static int singleUIDnb_release(struct inode *inode, struct file *filp)
{
spin_lock(&singleUIDnb_lock);
singleUIDnb_count--; /* nothing else */
spin_unlock(&singleUIDnb_lock);
if (singleUIDnb_count == 0)
wake_up_interruptible_sync(&singleUIDnb_wait); /* awake other uid's */
return 0;
}
ssize_t singleUIDnb_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_for_completion(&comp);
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
ssize_t singleUIDnb_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
complete(&comp);
return count; /* succeed, to avoid retrial */
}
struct file_operations singleUIDnb_fops = {
.owner = THIS_MODULE,
.read = singleUIDnb_read,
.write = singleUIDnb_write,
.open = singleUIDnb_open,
.release = singleUIDnb_release,
};
void singleUIDnb_cleanup(void)
{
#if 0
unregister_chrdev(complete_major, "complete");
#endif
//#if 0
dev_t devno = MKDEV(singleUIDnb_major, singleUIDnb_minor);
/* Get rid of our char dev entries */
if (singleUIDnb_cdev) {
cdev_del(singleUIDnb_cdev);
kfree(singleUIDnb_cdev);
}
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno,1);
//#endif
}
int singleUIDnb_init(void)
{
#if 0
int result;
/*
* Register your major, and accept a dynamic number
*/
result = register_chrdev(complete_major, "complete", &complete_fops);
if (result < 0)
return result;
if (complete_major == 0)
complete_major = result; /* dynamic */
return 0;
#endif
//#if 0
int result,err;
dev_t dev = 0;
if (singleUIDnb_major) {
dev = MKDEV(singleUIDnb_major, singleUIDnb_minor);
result = register_chrdev_region(dev, 1 , "singleUIDnb");
} else {
result = alloc_chrdev_region(&dev, singleUIDnb_minor , 1,
"singleUIDnb");
singleUIDnb_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "singleUIDnb: can't get major %d\n", singleUIDnb_major);
return result;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
//complete_cdev = cdev_alloc(); //cdev_alloc() and kmalloc() are both ok! use them as you want!
singleUIDnb_cdev = kmalloc( sizeof(struct cdev), GFP_KERNEL);
if (!singleUIDnb_cdev) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
cdev_init(singleUIDnb_cdev, &singleUIDnb_fops);
singleUIDnb_cdev->owner = THIS_MODULE;
err = cdev_add (singleUIDnb_cdev, dev, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding singleUIDnb_cdev", err);
return 0; /* succeed */
fail:
singleUIDnb_cleanup();
return result;
//#endif
}
module_init(singleUIDnb_init);
module_exit(singleUIDnb_cleanup);
MODULE_AUTHOR("Tekkaman Ninja");
MODULE_LICENSE("Dual BSD/GPL");
singleUID_testr.c
#include
#include
#include
#include
#include
int main()
{
int sculltest;
int code;
if ((sculltest = open("/dev/singleUID",O_RDONLY ))<0) {
printf("open singleUID error! code=%d \n",sculltest);
exit(1);
}
if ((code=read(sculltest , NULL , 0)) < 0) printf("read error! code=%d \n",code);
else printf("read ok! code=%d \n",code);
close(sculltest);
exit(0);
}
singleUID_testw.c
#include
#include
#include
#include
#include
int main()
{
int sculltest;
int code;
if ((sculltest = open("/dev/singleUID",O_WRONLY ))<0) {
printf("open singleUID error! code=%d \n",sculltest);
exit(1);
}
if ((code=write(sculltest , NULL , 0)) < 0 ) printf("write error! code=%d \n",code);
else printf("write ok! code=%d \n",code);
close(sculltest);
exit(0);
}
Arm平台实验:
[root@FriendlyARM /udisk]# insmod uonly.ko
[root@FriendlyARM /udisk]# cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
21 sg
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 s3c2410_serial
253 singleUIDnb
254 rtc
Block devices:
259 blkext
7 loop
8 sd
31 mtdblock
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[root@FriendlyARM /udisk]# mknod /dev/singleUID c 253 0
[root@FriendlyARM /udisk]# ./singleUID_testr & 这里两个读进程
[root@FriendlyARM /udisk]# count : 1
[root@FriendlyARM /udisk]# ./singleUID_testr &
[root@FriendlyARM /udisk]# count : 2
[root@FriendlyARM /udisk]# su gongzhi 转到另一个账号
[gongzhi@FriendlyARM gongzhi]# cd /udisk/
[gongzhi@FriendlyARM /udisk]# ./singleUID_testw
open singleUID error! code=-1
[gongzhi@FriendlyARM /udisk]# ./singleUID_testr &
失败1 因为read为非阻塞 所以一直等待root用户的权限消失
[gongzhi@FriendlyARM /udisk]# failed 1
[gongzhi@FriendlyARM /udisk]# ./singleUID_testr &
[gongzhi@FriendlyARM /udisk]# failed 1
[gongzhi@FriendlyARM /udisk]# exit
[root@FriendlyARM /udisk]# ./singleUID_testw
count : 3
write ok! code=0
[root@FriendlyARM /udisk]# read ok! code=0
[1] - Done ./singleUID_testr
[root@FriendlyARM /udisk]# ps
PID USER VSZ STAT COMMAND
1 root 3068 S init
2 root 0 SW [kthreadd]
3 root 0 SW [ksoftirqd/0]
4 root 0 SW [events/0]
5 root 0 SW [khelper]
11 root 0 SW [async/mgr]
209 root 0 SW [sync_supers]
211 root 0 SW [bdi-default]
213 root 0 SW [kblockd/0]
222 root 0 SW [khubd]
228 root 0 SW [kmmcd]
244 root 0 SW [rpciod/0]
251 root 0 SW [kswapd0]
298 root 0 SW [aio/0]
302 root 0 SW [nfsiod]
306 root 0 SW [crypto/0]
413 root 0 SW [mtdblockd]
537 root 0 SW [scsi_eh_0]
539 root 0 SW [usb-storage]
630 root 0 SW [usbhid_resumer]
674 root 3068 S syslogd
677 root 3328 S /usr/sbin/inetd
681 root 1940 S /usr/sbin/boa
707 root 13084 S /opt/Qtopia/bin/qpe
708 root 3392 S -/bin/sh
709 root 3068 S init
710 root 3068 S init
713 root 3068 S init
718 root 0 SW [flush-31:0]
728 root 1412 D ./singleUID_testr
731 gongzhi 1412 S ./singleUID_testr
732 gongzhi 1412 S ./singleUID_testr
734 root 3392 R ps
[root@FriendlyARM /udisk]# ./singleUID_testw
count : 2
write ok! code=0
[root@FriendlyARM /udisk]# read ok! code=0
failed 2
count : 1
failed 2
count : 2
[2] + Done ./singleUID_testr
[root@FriendlyARM /udisk]# ps
PID USER VSZ STAT COMMAND
1 root 3068 S init
2 root 0 SW [kthreadd]
3 root 0 SW [ksoftirqd/0]
4 root 0 SW [events/0]
5 root 0 SW [khelper]
11 root 0 SW [async/mgr]
209 root 0 SW [sync_supers]
211 root 0 SW [bdi-default]
213 root 0 SW [kblockd/0]
222 root 0 SW [khubd]
228 root 0 SW [kmmcd]
244 root 0 SW [rpciod/0]
251 root 0 SW [kswapd0]
298 root 0 SW [aio/0]
302 root 0 SW [nfsiod]
306 root 0 SW [crypto/0]
413 root 0 SW [mtdblockd]
537 root 0 SW [scsi_eh_0]
539 root 0 SW [usb-storage]
630 root 0 SW [usbhid_resumer]
674 root 3068 S syslogd
677 root 3328 S /usr/sbin/inetd
681 root 1940 S /usr/sbin/boa
707 root 13084 S /opt/Qtopia/bin/qpe
708 root 3392 S -/bin/sh
709 root 3068 S init
710 root 3068 S init
713 root 3068 S init
718 root 0 SW [flush-31:0]
731 gongzhi 1412 D ./singleUID_testr
732 gongzhi 1412 D ./singleUID_testr
736 root 3392 R ps
[root@FriendlyARM /udisk]# ./singleUID_testw
count : 3
write ok! code=0
[root@FriendlyARM /udisk]# read ok! code=0