title: Unable to write struct to user from kernel with custom module
body: <p>I am currently extending a character device driver (as a kernel module), and I'm attempting to add a new IOCTL command. All the command should do is print out the contents of a struct containing information about the task currently running in user space. As you can see in the top level <code>scull.c</code> file, I attempt to take some of the fields from the kernel's <code>current</code> macro, and place it into a custom struct called <code>TASKSTRUCT</code> (this is the alias, the original name is <code>taskstruct</code>). The output should resemble the following when running <code>./scull i</code> from the <code>src</code> directory:</p>
  <pre><code>Device (/dev/scull) opened
  Return value: 0
  state 0, stack 0xffffc90002200000, cpu 1, prio 120, sprio 120, nprio 120, 
  rtprio 0, pid 47924, tgid 47924, nv 2, niv 5
  Device (/dev/scull) closed
  </code></pre>
  <p>This is the current output, obviously indicating that something has gone wrong:</p>
  <pre><code>Device (/dev/scull) opened
  Return value: -1
  Device (/dev/scull) closed
  </code></pre>
  <p>When I run GDB, I find no evidence of a segmentation fault, just the above output. Below, I have included the files necessary to reproduce this problem.</p>
  <p><strong>/driver/scull.c</strong></p>
  <pre><code>/*
   * main.c -- the bare scull char module
   *
   * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
   * Copyright (C) 2001 O'Reilly &amp; Associates
   *
   * The source code in this file can be freely used, adapted,
   * and redistributed in source or binary form, so long as an
   * acknowledgment appears in derived source files.  The citation
   * should list that the code comes from the book &quot;Linux Device
   * Drivers&quot; by Alessandro Rubini and Jonathan Corbet, published
   * by O'Reilly &amp; Associates.   No warranty is attached;
   * we cannot take responsibility for errors or fitness for use.
   *
   */
  
  #include &lt;linux/module.h&gt;
  #include &lt;linux/moduleparam.h&gt;
  #include &lt;linux/init.h&gt;
  
  #include &lt;linux/kernel.h&gt;   /* printk() */
  #include &lt;linux/slab.h&gt;     /* kmalloc() */
  #include &lt;linux/fs.h&gt;       /* everything... */
  #include &lt;linux/errno.h&gt;    /* error codes */
  #include &lt;linux/types.h&gt;    /* size_t */
  #include &lt;linux/cdev.h&gt;
  
  #include &lt;linux/uaccess.h&gt;  /* copy_*_user */
  
  #include &lt;linux/sched.h&gt;
  #include &lt;asm/current.h&gt;
  
  #include &quot;scull.h&quot;      /* local definitions */
  #include &quot;access_ok_version.h&quot;
  #include &quot;taskstruct.h&quot;
  /*
   * Our parameters which can be set at load time.
   */
  
  static int scull_major =   SCULL_MAJOR;
  static int scull_minor =   0;
  static int scull_quantum = SCULL_QUANTUM;
  
  module_param(scull_major, int, S_IRUGO);
  module_param(scull_minor, int, S_IRUGO);
  module_param(scull_quantum, int, S_IRUGO);
  
  MODULE_AUTHOR(&quot;Author&quot;);
  MODULE_LICENSE(&quot;Dual BSD/GPL&quot;);
  
  static struct cdev scull_cdev;      /* Char device structure        */
  
  typedef struct TASKSTRUCT TASKSTRUCT;
  
  /*
   * Open and close
   */
  
  static int scull_open(struct inode *inode, struct file *filp)
  {
      printk(KERN_INFO &quot;scull open\n&quot;);
      return 0;          /* success */
  }
  
  static int scull_release(struct inode *inode, struct file *filp)
  {
      printk(KERN_INFO &quot;scull close\n&quot;);
      return 0;
  }
  
  /*
   * The ioctl() implementation
   */
  
  static long scull_ioctl(struct file *filp, unsigned int cmd,
          unsigned long arg)
  {
  
      int err = 0, tmp;
      int retval = 0;
      TASKSTRUCT info;
      
      /*
       * extract the type and number bitfields, and don't decode
       * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
       */
      if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
      if (_IOC_NR(cmd) &gt; SCULL_IOC_MAXNR) return -ENOTTY;
  
      /*
       * the direction is a bitmask, and VERIFY_WRITE catches R/W
       * transfers. `Type' is user-oriented, while
       * access_ok is kernel-oriented, so the concept of &quot;read&quot; and
       * &quot;write&quot; is reversed
       */
      if (_IOC_DIR(cmd) &amp; _IOC_READ)
          err = !access_ok_wrapper(VERIFY_WRITE, (void __user *)arg,
                  _IOC_SIZE(cmd));
      else if (_IOC_DIR(cmd) &amp; _IOC_WRITE)
          err =  !access_ok_wrapper(VERIFY_READ, (void __user *)arg,
                  _IOC_SIZE(cmd));
      if (err) return -EFAULT;
  
      switch(cmd) {
      case SCULL_IOCIQUANTUM:
          info.state = current-&gt;state;
          info.stack = current-&gt;stack;
          info.cpu = current-&gt;nr_cpus_allowed;
          info.prio = current-&gt;prio;
          info.static_prio = current-&gt;static_prio;
          info.normal_prio = current-&gt;normal_prio;
          info.rt_priority = current-&gt;rt_priority;
          info.pid = current-&gt;pid;
          info.tgid = current-&gt;tgid;
          info.nvcsw = current-&gt;nvcsw;
          info.nivcsw = current-&gt;nivcsw;
          retval = copy_to_user((int __user *)arg,&amp;info,sizeof(info));
          //printk(KERN_INFO &quot;copy_to_user: %d\n&quot;,retval);
          if(retval == 0) {
              printk(KERN_INFO &quot;copy_to_user worked!&quot;);
          }}
          printk(KERN_INFO &quot;size of info: %ld\n&quot;,sizeof(info));
          break;
  
      default:  /* redundant, as cmd was checked against MAXNR */
          return -ENOTTY;
      }
      return retval;
  
  }
  
  
  struct file_operations scull_fops = {
      .owner =    THIS_MODULE,
      .unlocked_ioctl = scull_ioctl,
      .open =     scull_open,
      .release =  scull_release,
  };
  
  /*
   * Finally, the module stuff
   */
  
  /*
   * The cleanup function is used to handle initialization failures as well.
   * Thefore, it must be careful to work correctly even if some of the items
   * have not been initialized
   */
  void scull_cleanup_module(void)
  {
      dev_t devno = MKDEV(scull_major, scull_minor);
  
      /* Get rid of the char dev entry */
      cdev_del(&amp;scull_cdev);
  
      /* cleanup_module is never called if registering failed */
      unregister_chrdev_region(devno, 1);
  }
  
  
  int scull_init_module(void)
  {
      int result;
      dev_t dev = 0;
  
      /*
       * Get a range of minor numbers to work with, asking for a dynamic
       * major unless directed otherwise at load time.
       */
      if (scull_major) {
          dev = MKDEV(scull_major, scull_minor);
          result = register_chrdev_region(dev, 1, &quot;scull&quot;);
      } else {
          result = alloc_chrdev_region(&amp;dev, scull_minor, 1, &quot;scull&quot;);
          scull_major = MAJOR(dev);
      }
      if (result &lt; 0) {
          printk(KERN_WARNING &quot;scull: can't get major %d\n&quot;, scull_major);
          return result;
      }
  
      cdev_init(&amp;scull_cdev, &amp;scull_fops);
      scull_cdev.owner = THIS_MODULE;
      result = cdev_add (&amp;scull_cdev, dev, 1);
      /* Fail gracefully if need be */
      if (result) {
          printk(KERN_NOTICE &quot;Error %d adding scull character device&quot;, result);
          goto fail;
      }
  
      return 0; /* succeed */
  
    fail:
      scull_cleanup_module();
      return result;
  }
  
  module_init(scull_init_module);
  module_exit(scull_cleanup_module);
  </code></pre>
  <p><strong>/driver/scull.h</strong></p>
  <pre><code>/*
   * scull.h -- definitions for the char module
   *
   * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
   * Copyright (C) 2001 O'Reilly &amp; Associates
   *
   * The source code in this file can be freely used, adapted,
   * and redistributed in source or binary form, so long as an
   * acknowledgment appears in derived source files.  The citation
   * should list that the code comes from the book &quot;Linux Device
   * Drivers&quot; by Alessandro Rubini and Jonathan Corbet, published
   * by O'Reilly &amp; Associates.   No warranty is attached;
   * we cannot take responsibility for errors or fitness for use.
   *
   * $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
   */
  
  #ifndef _SCULL_H_
  #define _SCULL_H_
  
  #include &lt;linux/ioctl.h&gt; /* needed for the _IOW etc stuff used later */
  #include &quot;taskstruct.h&quot;
  
  #ifndef SCULL_MAJOR
  #define SCULL_MAJOR 0   /* dynamic major by default */
  #endif
  
  
  /*
   * SCULL_QUANTUM
   */
  #ifndef SCULL_QUANTUM
  #define SCULL_QUANTUM 4000
  #endif
  
  
  /*
   * Ioctl definitions
   */
  
  /* Use 'k' as magic number */
  #define SCULL_IOC_MAGIC  'k'
  
  #define SCULL_IOCRESET    _IO(SCULL_IOC_MAGIC, 0)
  
  /*
   * I (new) means &quot;Info&quot;: returns task_struct of task currently running in user space
   */
  #define SCULL_IOCIQUANTUM _IOR(SCULL_IOC_MAGIC,   1, struct TASKSTRUCT)
  
  /* ... more to come */
  
  #define SCULL_IOC_MAXNR 1
  
  #endif /* _SCULL_H_ */
  </code></pre>
  <p><strong>/driver/Makefile</strong> (<code>driver</code> is the folder containing the code for the module)</p>
  <pre><code># Comment/uncomment the following line to disable/enable debugging
  #DEBUG = y
  
  
  # Add your debugging flag (or not) to CFLAGS
  ifeq ($(DEBUG),y)
    DEBFLAGS = -O0 -g -DSCULL_DEBUG # &quot;-O&quot; is needed to expand inlines
  else
    DEBFLAGS = -O2
  endif
  
  EXTRA_CFLAGS += $(DEBFLAGS)
  
  ifneq ($(KERNELRELEASE),)
  # call from kernel build system
  
  obj-m   := scull.o
  
  else
  
  KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  PWD       := $(shell pwd)
  
  modules:
      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  
  endif
  
  
  
  clean:
      rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
  
  depend .depend dep:
      $(CC) $(EXTRA_CFLAGS) -M *.c &gt; .depend
  
  
  ifeq (.depend,$(wildcard .depend))
  include .depend
  endif
  </code></pre>
  <p><strong>/driver/taskstruct.h</strong></p>
  <pre><code>#ifndef TASKSTRUCT_H
  #define TASKSTRUCT_H
  
  typedef struct TASKSTRUCT {
      long state;
      void *stack;
      unsigned int cpu;
      int prio;
      int static_prio;
      int normal_prio;
      unsigned int rt_priority;
      pid_t pid;
      pid_t tgid;
      unsigned long nvcsw;
      unsigned long nivcsw;
  };
  
  #endif
  </code></pre>
  <p><strong>/src/scull.c</strong> (<code>src</code> contains the code to test the module)</p>
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/ioctl.h&gt;
  
  #include &quot;scull.h&quot;
  #include &quot;taskstruct.h&quot;
  
  #define CDEV_NAME &quot;/dev/scull&quot;
  
  /* Quantum command line option */
  static int g_quantum;
  
  static void usage(const char *cmd)
  {
      printf(&quot;Usage&quot;);
  }
  
  typedef int cmd_t;
  
  static cmd_t parse_arguments(int argc, const char **argv)
  {
      cmd_t cmd;
  
      if (argc &lt; 2) {
          fprintf(stderr, &quot;%s: Invalid number of arguments\n&quot;, argv[0]);
          cmd = -1;
          goto ret;
      }
  
      /* Parse command and optional int argument */
      cmd = argv[1][0];
      switch (cmd) {
      case 'i':
          break;
      default:
          fprintf(stderr, &quot;%s: Invalid command\n&quot;, argv[0]);
          cmd = -1;
      }
  
  ret:
      if (cmd &lt; 0 || cmd == 'h') {
          usage(argv[0]);
          exit((cmd == 'h')? EXIT_SUCCESS : EXIT_FAILURE);
      }
      return cmd;
  }
  
  static int do_op(int fd, cmd_t cmd)
  {
      int ret, q;
      char *s;
      //task_struct info;
  
      switch (cmd) {
      case 'i':
          ret = ioctl(fd, SCULL_IOCIQUANTUM, &amp;s);
          printf(&quot;Return value: %d\n&quot;,ret);
          if(ret == 0)
              printf(&quot;%s\n&quot;,s);
          ret = 0;
          break;
  
      default:
          /* Should never occur */
          abort();
          ret = -1; /* Keep the compiler happy */
      }
  
      if (ret != 0)
          perror(&quot;ioctl&quot;);
      return ret;
  }
  
  int main(int argc, const char **argv)
  {
      int fd, ret;
      cmd_t cmd;
  
      cmd = parse_arguments(argc, argv);
  
      fd = open(CDEV_NAME, O_RDONLY);
      if (fd &lt; 0) {
          perror(&quot;cdev open&quot;);
          return EXIT_FAILURE;
      }
  
      printf(&quot;Device (%s) opened\n&quot;, CDEV_NAME);
  
      ret = do_op(fd, cmd);
  
      if (close(fd) != 0) {
          perror(&quot;cdev close&quot;);
          return EXIT_FAILURE;
      }
  
      printf(&quot;Device (%s) closed\n&quot;, CDEV_NAME);
  
      return (ret != 0)? EXIT_FAILURE : EXIT_SUCCESS;
  }
  </code></pre>
  <p><strong>/src/Makefile</strong></p>
  <pre><code>CFLAGS=-O2 -Wall -I../driver
  TGT=scull
  
  
  .PHONY: clean
  
  all: $(TGT)
  
  clean:
      rm -f *.o $(TGT)
  </code></pre>
  <p><em>(<code>src</code> also contains a copy of <code>taskstruct.h</code>)</em></p>
  <p>Any help would be greatly appreciated.</p>