]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'writable_limits' of git://decibel.fi.muni.cz/~xslaby/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Aug 2010 19:07:51 +0000 (12:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Aug 2010 19:07:51 +0000 (12:07 -0700)
* 'writable_limits' of git://decibel.fi.muni.cz/~xslaby/linux:
  unistd: add __NR_prlimit64 syscall numbers
  rlimits: implement prlimit64 syscall
  rlimits: switch more rlimit syscalls to do_prlimit
  rlimits: redo do_setrlimit to more generic do_prlimit
  rlimits: add rlimit64 structure
  rlimits: do security check under task_lock
  rlimits: allow setrlimit to non-current tasks
  rlimits: split sys_setrlimit
  rlimits: selinux, do rlimits changes under task_lock
  rlimits: make sure ->rlim_max never grows in sys_setrlimit
  rlimits: add task_struct to update_rlimit_cpu
  rlimits: security, add task_struct to setrlimit

Fix up various system call number conflicts.  We not only added fanotify
system calls in the meantime, but asm-generic/unistd.h added a wait4
along with a range of reserved per-architecture system calls.

1  2 
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/syscall_table_32.S
include/asm-generic/unistd.h
include/linux/security.h
include/linux/syscalls.h
kernel/posix-cpu-timers.c
security/capability.c
security/security.c
security/selinux/hooks.c

index 17cf65c948048cbd22257005b9ebec5e50a86335,a88e31d1836ea18fa30c5034619a0d9ad704dca6..91dc4bb130321cf23ae8c3f5e4b2d5808872c84d
@@@ -842,6 -842,5 +842,7 @@@ ia32_sys_call_table
        .quad compat_sys_rt_tgsigqueueinfo      /* 335 */
        .quad sys_perf_event_open
        .quad compat_sys_recvmmsg
 +      .quad sys_fanotify_init
 +      .quad sys32_fanotify_mark
+       .quad sys_prlimit64
  ia32_syscall_end:
index 80b799cd74f7ad8be7461dc21f09827ad107c582,35e0cb151b6935c1f6d3a9f216a3460f3745b874..b766a5e8ba0e7802501b049034394a343216cf4a
  #define __NR_rt_tgsigqueueinfo        335
  #define __NR_perf_event_open  336
  #define __NR_recvmmsg         337
 -#define __NR_prlimit64                338
 +#define __NR_fanotify_init    338
 +#define __NR_fanotify_mark    339
++#define __NR_prlimit64                340
  
  #ifdef __KERNEL__
  
- #define NR_syscalls 340
 -#define NR_syscalls 339
++#define NR_syscalls 341
  
  #define __ARCH_WANT_IPC_PARSE_VERSION
  #define __ARCH_WANT_OLD_READDIR
index 5b7b1d5856167457209b2eddb75ea19593aeac26,570bf5eae564059b4517d7d7e0a1d423b2348d61..363e9b8a715b6d5144ebc8135d65dc75ce9e9e5c
@@@ -663,10 -663,8 +663,12 @@@ __SYSCALL(__NR_rt_tgsigqueueinfo, sys_r
  __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
  #define __NR_recvmmsg                         299
  __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 -#define __NR_prlimit64                                300
 +#define __NR_fanotify_init                    300
 +__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 +#define __NR_fanotify_mark                    301
 +__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
++#define __NR_prlimit64                                302
+ __SYSCALL(__NR_prlimit64, sys_prlimit64)
  
  #ifndef __NO_STUBS
  #define __ARCH_WANT_OLD_READDIR
index 07ad5eb7cc5c57715e6229ac3513ae4a5de556a8,eca1d7d23ab56b5a5c191ade685c0685bbbfeac9..4802accb9d8d08be4cad495a923943b32bf21d4a
@@@ -337,5 -337,4 +337,6 @@@ ENTRY(sys_call_table
        .long sys_rt_tgsigqueueinfo     /* 335 */
        .long sys_perf_event_open
        .long sys_recvmmsg
 +      .long sys_fanotify_init
 +      .long sys_fanotify_mark
+       .long sys_prlimit64
index c17cebc499522d160eacb93807593112e23673ca,0dfd517e5ec93292ed417b91497596e063bfbcfb..e1898090f22c88cf2eaaa09bb2f7ade8edf6eba9
@@@ -18,7 -18,7 +18,7 @@@
  #define __SYSCALL(x, y)
  #endif
  
 -#if __BITS_PER_LONG == 32
 +#if __BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT)
  #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
  #else
  #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
@@@ -241,13 -241,8 +241,13 @@@ __SYSCALL(__NR_sync, sys_sync
  __SYSCALL(__NR_fsync, sys_fsync)
  #define __NR_fdatasync 83
  __SYSCALL(__NR_fdatasync, sys_fdatasync)
 +#ifdef __ARCH_WANT_SYNC_FILE_RANGE2
 +#define __NR_sync_file_range2 84
 +__SYSCALL(__NR_sync_file_range2, sys_sync_file_range2)
 +#else
  #define __NR_sync_file_range 84
 -__SYSCALL(__NR_sync_file_range, sys_sync_file_range) /* .long sys_sync_file_range2, */
 +__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
 +#endif
  
  /* fs/timerfd.c */
  #define __NR_timerfd_create 85
@@@ -585,7 -580,7 +585,7 @@@ __SYSCALL(__NR_execve, sys_execve) /* .
  __SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
  /* mm/fadvise.c */
  #define __NR3264_fadvise64 223
 -__SC_3264(__NR3264_fadvise64, sys_fadvise64_64, sys_fadvise64)
 +__SYSCALL(__NR3264_fadvise64, sys_fadvise64_64)
  
  /* mm/, CONFIG_MMU only */
  #ifndef __ARCH_NOMMU
@@@ -631,18 -626,11 +631,20 @@@ __SYSCALL(__NR_perf_event_open, sys_per
  __SYSCALL(__NR_accept4, sys_accept4)
  #define __NR_recvmmsg 243
  __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 -#define __NR_prlimit64 244
 +
 +/*
 + * Architectures may provide up to 16 syscalls of their own
 + * starting with this value.
 + */
 +#define __NR_arch_specific_syscall 244
 +
 +#define __NR_wait4 260
 +__SYSCALL(__NR_wait4, sys_wait4)
++#define __NR_prlimit64 261
+ __SYSCALL(__NR_prlimit64, sys_prlimit64)
  
  #undef __NR_syscalls
- #define __NR_syscalls 261
 -#define __NR_syscalls 245
++#define __NR_syscalls 262
  
  /*
   * All syscalls below here should go away really,
@@@ -708,8 -696,7 +710,8 @@@ __SYSCALL(__NR_signalfd, sys_signalfd
  #define __NR_syscalls (__NR_signalfd+1)
  #endif /* __ARCH_WANT_SYSCALL_NO_FLAGS */
  
 -#if __BITS_PER_LONG == 32 && defined(__ARCH_WANT_SYSCALL_OFF_T)
 +#if (__BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT)) && \
 +     defined(__ARCH_WANT_SYSCALL_OFF_T)
  #define __NR_sendfile 1046
  __SYSCALL(__NR_sendfile, sys_sendfile)
  #define __NR_ftruncate 1047
@@@ -755,7 -742,6 +757,7 @@@ __SYSCALL(__NR_getpgrp, sys_getpgrp
  __SYSCALL(__NR_pause, sys_pause)
  #define __NR_time 1062
  #define __ARCH_WANT_SYS_TIME
 +#define __ARCH_WANT_COMPAT_SYS_TIME
  __SYSCALL(__NR_time, sys_time)
  #define __NR_utime 1063
  #define __ARCH_WANT_SYS_UTIME
@@@ -779,8 -765,8 +781,8 @@@ __SYSCALL(__NR_epoll_wait, sys_epoll_wa
  __SYSCALL(__NR_ustat, sys_ustat)
  #define __NR_vfork 1071
  __SYSCALL(__NR_vfork, sys_vfork)
 -#define __NR_wait4 1072
 -__SYSCALL(__NR_wait4, sys_wait4)
 +#define __NR_oldwait4 1072
 +__SYSCALL(__NR_oldwait4, sys_wait4)
  #define __NR_recv 1073
  __SYSCALL(__NR_recv, sys_recv)
  #define __NR_send 1074
@@@ -817,7 -803,7 +819,7 @@@ __SYSCALL(__NR_fork, sys_ni_syscall
   * Here we map the numbers so that both versions
   * use the same syscall table layout.
   */
 -#if __BITS_PER_LONG == 64
 +#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT)
  #define __NR_fcntl __NR3264_fcntl
  #define __NR_statfs __NR3264_statfs
  #define __NR_fstatfs __NR3264_fstatfs
  #endif
  #define __ARCH_WANT_SYS_RT_SIGACTION
  #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 +#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
  
  /*
   * "Conditional" syscalls
diff --combined include/linux/security.h
index 5bcb395a49d40084b5625d3bfa920f9bc62fed79,1a3eb5ff4357bccea3a33f5a1fdb08b2b4f9d3a7..a22219afff092952bbe276cb9da1d0509ddf196c
@@@ -23,7 -23,6 +23,7 @@@
  #define __LINUX_SECURITY_H
  
  #include <linux/fs.h>
 +#include <linux/fsnotify.h>
  #include <linux/binfmts.h>
  #include <linux/signal.h>
  #include <linux/resource.h>
@@@ -471,6 -470,8 +471,6 @@@ static inline void security_free_mnt_op
   * @path_truncate:
   *    Check permission before truncating a file.
   *    @path contains the path structure for the file.
 - *    @length is the new length of the file.
 - *    @time_attrs is the flags passed to do_truncate().
   *    Return 0 if permission is granted.
   * @inode_getattr:
   *    Check permission before obtaining file attributes.
@@@ -1411,7 -1412,8 +1411,7 @@@ struct security_operations 
        int (*path_rmdir) (struct path *dir, struct dentry *dentry);
        int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
                           unsigned int dev);
 -      int (*path_truncate) (struct path *path, loff_t length,
 -                            unsigned int time_attrs);
 +      int (*path_truncate) (struct path *path);
        int (*path_symlink) (struct path *dir, struct dentry *dentry,
                             const char *old_name);
        int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
        int (*task_setnice) (struct task_struct *p, int nice);
        int (*task_setioprio) (struct task_struct *p, int ioprio);
        int (*task_getioprio) (struct task_struct *p);
-       int (*task_setrlimit) (unsigned int resource, struct rlimit *new_rlim);
+       int (*task_setrlimit) (struct task_struct *p, unsigned int resource,
+                       struct rlimit *new_rlim);
        int (*task_setscheduler) (struct task_struct *p, int policy,
                                  struct sched_param *lp);
        int (*task_getscheduler) (struct task_struct *p);
@@@ -1749,7 -1752,8 +1750,8 @@@ void security_task_getsecid(struct task
  int security_task_setnice(struct task_struct *p, int nice);
  int security_task_setioprio(struct task_struct *p, int ioprio);
  int security_task_getioprio(struct task_struct *p);
- int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim);
+ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim);
  int security_task_setscheduler(struct task_struct *p,
                                int policy, struct sched_param *lp);
  int security_task_getscheduler(struct task_struct *p);
@@@ -2311,7 -2315,8 +2313,8 @@@ static inline int security_task_getiopr
        return 0;
  }
  
- static inline int security_task_setrlimit(unsigned int resource,
+ static inline int security_task_setrlimit(struct task_struct *p,
+                                         unsigned int resource,
                                          struct rlimit *new_rlim)
  {
        return 0;
@@@ -2804,7 -2809,8 +2807,7 @@@ int security_path_mkdir(struct path *di
  int security_path_rmdir(struct path *dir, struct dentry *dentry);
  int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
                        unsigned int dev);
 -int security_path_truncate(struct path *path, loff_t length,
 -                         unsigned int time_attrs);
 +int security_path_truncate(struct path *path);
  int security_path_symlink(struct path *dir, struct dentry *dentry,
                          const char *old_name);
  int security_path_link(struct dentry *old_dentry, struct path *new_dir,
@@@ -2838,7 -2844,8 +2841,7 @@@ static inline int security_path_mknod(s
        return 0;
  }
  
 -static inline int security_path_truncate(struct path *path, loff_t length,
 -                                       unsigned int time_attrs)
 +static inline int security_path_truncate(struct path *path)
  {
        return 0;
  }
diff --combined include/linux/syscalls.h
index 2ab198a1e38d80dfd35cf536a85fc14b5485b10c,a60943be4270d92ab75795ad8583a251e4375e4f..1b67bd333b5e4097a9d6debb6498219006c01957
@@@ -35,6 -35,7 +35,7 @@@ struct oldold_utsname
  struct old_utsname;
  struct pollfd;
  struct rlimit;
+ struct rlimit64;
  struct rusage;
  struct sched_param;
  struct sel_arg_struct;
@@@ -124,8 -125,7 +125,8 @@@ extern struct trace_event_functions ent
  extern struct trace_event_functions exit_syscall_print_funcs;
  
  #define SYSCALL_TRACE_ENTER_EVENT(sname)                              \
 -      static struct syscall_metadata __syscall_meta_##sname;          \
 +      static struct syscall_metadata                                  \
 +      __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
        static struct ftrace_event_call                                 \
        __attribute__((__aligned__(4))) event_enter_##sname;            \
        static struct ftrace_event_call __used                          \
        }
  
  #define SYSCALL_TRACE_EXIT_EVENT(sname)                                       \
 -      static struct syscall_metadata __syscall_meta_##sname;          \
 +      static struct syscall_metadata                                  \
 +      __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
        static struct ftrace_event_call                                 \
        __attribute__((__aligned__(4))) event_exit_##sname;             \
        static struct ftrace_event_call __used                          \
                .enter_event    = &event_enter_##sname,         \
                .exit_event     = &event_exit_##sname,          \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
 -              .exit_fields    = LIST_HEAD_INIT(__syscall_meta_##sname.exit_fields), \
        };
  
  #define SYSCALL_DEFINE0(sname)                                        \
                .enter_event    = &event_enter__##sname,        \
                .exit_event     = &event_exit__##sname,         \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
 -              .exit_fields    = LIST_HEAD_INIT(__syscall_meta__##sname.exit_fields), \
        };                                                      \
        asmlinkage long sys_##sname(void)
  #else
@@@ -644,6 -645,9 +645,9 @@@ asmlinkage long sys_old_getrlimit(unsig
  #endif
  asmlinkage long sys_setrlimit(unsigned int resource,
                                struct rlimit __user *rlim);
+ asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource,
+                               const struct rlimit64 __user *new_rlim,
+                               struct rlimit64 __user *old_rlim);
  asmlinkage long sys_getrusage(int who, struct rusage __user *ru);
  asmlinkage long sys_umask(int mask);
  
@@@ -811,10 -815,6 +815,10 @@@ asmlinkage long sys_pselect6(int, fd_se
  asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
                          struct timespec __user *, const sigset_t __user *,
                          size_t);
 +asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags);
 +asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
 +                                u64 mask, int fd,
 +                                const char  __user *pathname);
  
  int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
  
index f66bdd33a6c61f58f033732d24b9a3a7d19ae989,0513900995cebfeb8d2cabf1d2b57591d31999c4..6842eeba58798276d61b469072e50e0d6116bbac
   * siglock protection since other code may update expiration cache as
   * well.
   */
- void update_rlimit_cpu(unsigned long rlim_new)
+ void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
  {
        cputime_t cputime = secs_to_cputime(rlim_new);
  
-       spin_lock_irq(&current->sighand->siglock);
-       set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL);
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_lock_irq(&task->sighand->siglock);
+       set_process_cpu_timer(task, CPUCLOCK_PROF, &cputime, NULL);
+       spin_unlock_irq(&task->sighand->siglock);
  }
  
  static int check_clock(const clockid_t which_clock)
@@@ -232,24 -232,31 +232,24 @@@ static int cpu_clock_sample(const clock
  
  void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
  {
 -      struct sighand_struct *sighand;
 -      struct signal_struct *sig;
 +      struct signal_struct *sig = tsk->signal;
        struct task_struct *t;
  
 -      *times = INIT_CPUTIME;
 +      times->utime = sig->utime;
 +      times->stime = sig->stime;
 +      times->sum_exec_runtime = sig->sum_sched_runtime;
  
        rcu_read_lock();
 -      sighand = rcu_dereference(tsk->sighand);
 -      if (!sighand)
 +      /* make sure we can trust tsk->thread_group list */
 +      if (!likely(pid_alive(tsk)))
                goto out;
  
 -      sig = tsk->signal;
 -
        t = tsk;
        do {
                times->utime = cputime_add(times->utime, t->utime);
                times->stime = cputime_add(times->stime, t->stime);
                times->sum_exec_runtime += t->se.sum_exec_runtime;
 -
 -              t = next_thread(t);
 -      } while (t != tsk);
 -
 -      times->utime = cputime_add(times->utime, sig->utime);
 -      times->stime = cputime_add(times->stime, sig->stime);
 -      times->sum_exec_runtime += sig->sum_sched_runtime;
 +      } while_each_thread(tsk, t);
  out:
        rcu_read_unlock();
  }
@@@ -1272,6 -1279,10 +1272,6 @@@ static inline int fastpath_timer_check(
  {
        struct signal_struct *sig;
  
 -      /* tsk == current, ensure it is safe to use ->signal/sighand */
 -      if (unlikely(tsk->exit_state))
 -              return 0;
 -
        if (!task_cputime_zero(&tsk->cputime_expires)) {
                struct task_cputime task_sample = {
                        .utime = tsk->utime,
        if (sig->cputimer.running) {
                struct task_cputime group_sample;
  
 -              thread_group_cputimer(tsk, &group_sample);
 +              spin_lock(&sig->cputimer.lock);
 +              group_sample = sig->cputimer.cputime;
 +              spin_unlock(&sig->cputimer.lock);
 +
                if (task_cputime_expired(&group_sample, &sig->cputime_expires))
                        return 1;
        }
@@@ -1307,7 -1315,6 +1307,7 @@@ void run_posix_cpu_timers(struct task_s
  {
        LIST_HEAD(firing);
        struct k_itimer *timer, *next;
 +      unsigned long flags;
  
        BUG_ON(!irqs_disabled());
  
        if (!fastpath_timer_check(tsk))
                return;
  
 -      spin_lock(&tsk->sighand->siglock);
 +      if (!lock_task_sighand(tsk, &flags))
 +              return;
        /*
         * Here we take off tsk->signal->cpu_timers[N] and
         * tsk->cpu_timers[N] all the timers that are firing, and
         * that gets the timer lock before we do will give it up and
         * spin until we've taken care of that timer below.
         */
 -      spin_unlock(&tsk->sighand->siglock);
 +      unlock_task_sighand(tsk, &flags);
  
        /*
         * Now that all the timers on our list have the firing flag,
diff --combined security/capability.c
index a0bbf30fb6dc93de4fe29da540be3533e797dede,7e468263f2dec91cbfd68662179187605f527e11..95a6599a37bb3ae0737779d16d9a0d811d5bfc82
@@@ -27,7 -27,7 +27,7 @@@ static int cap_quota_on(struct dentry *
        return 0;
  }
  
 -static int cap_bprm_check_security (struct linux_binprm *bprm)
 +static int cap_bprm_check_security(struct linux_binprm *bprm)
  {
        return 0;
  }
@@@ -268,7 -268,8 +268,7 @@@ static int cap_path_rename(struct path 
        return 0;
  }
  
 -static int cap_path_truncate(struct path *path, loff_t length,
 -                           unsigned int time_attrs)
 +static int cap_path_truncate(struct path *path)
  {
        return 0;
  }
@@@ -411,7 -412,8 +411,8 @@@ static int cap_task_getioprio(struct ta
        return 0;
  }
  
- static int cap_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+ static int cap_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim)
  {
        return 0;
  }
diff --combined security/security.c
index 7461b1bc296ccfd5a85f7c180644de07044f07c5,aa510609a95543deffc0e2afffb9eb709e539faa..c53949f17d9e0dddc0601032576ef2922fb88f86
@@@ -417,11 -417,12 +417,11 @@@ int security_path_rename(struct path *o
                                         new_dentry);
  }
  
 -int security_path_truncate(struct path *path, loff_t length,
 -                         unsigned int time_attrs)
 +int security_path_truncate(struct path *path)
  {
        if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
                return 0;
 -      return security_ops->path_truncate(path, length, time_attrs);
 +      return security_ops->path_truncate(path);
  }
  
  int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
@@@ -619,13 -620,7 +619,13 @@@ void security_inode_getsecid(const stru
  
  int security_file_permission(struct file *file, int mask)
  {
 -      return security_ops->file_permission(file, mask);
 +      int ret;
 +
 +      ret = security_ops->file_permission(file, mask);
 +      if (ret)
 +              return ret;
 +
 +      return fsnotify_perm(file, mask);
  }
  
  int security_file_alloc(struct file *file)
@@@ -689,13 -684,7 +689,13 @@@ int security_file_receive(struct file *
  
  int security_dentry_open(struct file *file, const struct cred *cred)
  {
 -      return security_ops->dentry_open(file, cred);
 +      int ret;
 +
 +      ret = security_ops->dentry_open(file, cred);
 +      if (ret)
 +              return ret;
 +
 +      return fsnotify_perm(file, MAY_OPEN);
  }
  
  int security_task_create(unsigned long clone_flags)
@@@ -780,9 -769,10 +780,10 @@@ int security_task_getioprio(struct task
        return security_ops->task_getioprio(p);
  }
  
- int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim)
  {
-       return security_ops->task_setrlimit(resource, new_rlim);
+       return security_ops->task_setrlimit(p, resource, new_rlim);
  }
  
  int security_task_setscheduler(struct task_struct *p,
diff --combined security/selinux/hooks.c
index 9b40f4c0ac7032e3d80d2508ba96024fd28d2512,2a8a0a915ff38b49bcf98ad36f249b0cef7f5d00..42043f96e54f69d0d2cb2ab1f063a7e638d0786f
@@@ -87,6 -87,9 +87,6 @@@
  #include "netlabel.h"
  #include "audit.h"
  
 -#define XATTR_SELINUX_SUFFIX "selinux"
 -#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 -
  #define NUM_SEL_MNT_OPTS 5
  
  extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@@ -185,7 -188,7 +185,7 @@@ static inline u32 task_sid(const struc
   */
  static inline u32 current_sid(void)
  {
 -      const struct task_security_struct *tsec = current_cred()->security;
 +      const struct task_security_struct *tsec = current_security();
  
        return tsec->sid;
  }
@@@ -276,6 -279,32 +276,6 @@@ static void superblock_free_security(st
        kfree(sbsec);
  }
  
 -static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 -{
 -      struct sk_security_struct *sksec;
 -
 -      sksec = kzalloc(sizeof(*sksec), priority);
 -      if (!sksec)
 -              return -ENOMEM;
 -
 -      sksec->peer_sid = SECINITSID_UNLABELED;
 -      sksec->sid = SECINITSID_UNLABELED;
 -      sk->sk_security = sksec;
 -
 -      selinux_netlbl_sk_security_reset(sksec);
 -
 -      return 0;
 -}
 -
 -static void sk_free_security(struct sock *sk)
 -{
 -      struct sk_security_struct *sksec = sk->sk_security;
 -
 -      sk->sk_security = NULL;
 -      selinux_netlbl_sk_security_free(sksec);
 -      kfree(sksec);
 -}
 -
  /* The security server must be initialized before
     any labeling or access decisions can be provided. */
  extern int ss_initialized;
@@@ -1555,7 -1584,8 +1555,7 @@@ static int may_create(struct inode *dir
                      struct dentry *dentry,
                      u16 tclass)
  {
 -      const struct cred *cred = current_cred();
 -      const struct task_security_struct *tsec = cred->security;
 +      const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
@@@ -1776,9 -1806,27 +1776,9 @@@ static inline u32 open_file_to_av(struc
  {
        u32 av = file_to_av(file);
  
 -      if (selinux_policycap_openperm) {
 -              mode_t mode = file->f_path.dentry->d_inode->i_mode;
 -              /*
 -               * lnk files and socks do not really have an 'open'
 -               */
 -              if (S_ISREG(mode))
 -                      av |= FILE__OPEN;
 -              else if (S_ISCHR(mode))
 -                      av |= CHR_FILE__OPEN;
 -              else if (S_ISBLK(mode))
 -                      av |= BLK_FILE__OPEN;
 -              else if (S_ISFIFO(mode))
 -                      av |= FIFO_FILE__OPEN;
 -              else if (S_ISDIR(mode))
 -                      av |= DIR__OPEN;
 -              else if (S_ISSOCK(mode))
 -                      av |= SOCK_FILE__OPEN;
 -              else
 -                      printk(KERN_ERR "SELinux: WARNING: inside %s with "
 -                              "unknown mode:%o\n", __func__, mode);
 -      }
 +      if (selinux_policycap_openperm)
 +              av |= FILE__OPEN;
 +
        return av;
  }
  
@@@ -2135,7 -2183,8 +2135,7 @@@ static int selinux_bprm_set_creds(struc
  
  static int selinux_bprm_secureexec(struct linux_binprm *bprm)
  {
 -      const struct cred *cred = current_cred();
 -      const struct task_security_struct *tsec = cred->security;
 +      const struct task_security_struct *tsec = current_security();
        u32 sid, osid;
        int atsecure = 0;
  
@@@ -2284,12 -2333,15 +2284,15 @@@ static void selinux_bprm_committing_cre
        rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
                          PROCESS__RLIMITINH, NULL);
        if (rc) {
+               /* protect against do_prlimit() */
+               task_lock(current);
                for (i = 0; i < RLIM_NLIMITS; i++) {
                        rlim = current->signal->rlim + i;
                        initrlim = init_task.signal->rlim + i;
                        rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
                }
-               update_rlimit_cpu(current->signal->rlim[RLIMIT_CPU].rlim_cur);
+               task_unlock(current);
+               update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
        }
  }
  
@@@ -2510,7 -2562,8 +2513,7 @@@ static int selinux_inode_init_security(
                                       char **name, void **value,
                                       size_t *len)
  {
 -      const struct cred *cred = current_cred();
 -      const struct task_security_struct *tsec = cred->security;
 +      const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
@@@ -2626,26 -2679,14 +2629,26 @@@ static int selinux_inode_follow_link(st
  static int selinux_inode_permission(struct inode *inode, int mask)
  {
        const struct cred *cred = current_cred();
 +      struct common_audit_data ad;
 +      u32 perms;
 +      bool from_access;
  
 -      if (!mask) {
 -              /* No permission to check.  Existence test. */
 +      from_access = mask & MAY_ACCESS;
 +      mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
 +
 +      /* No permission to check.  Existence test. */
 +      if (!mask)
                return 0;
 -      }
  
 -      return inode_has_perm(cred, inode,
 -                            file_mask_to_av(inode->i_mode, mask), NULL);
 +      COMMON_AUDIT_DATA_INIT(&ad, FS);
 +      ad.u.fs.inode = inode;
 +
 +      if (from_access)
 +              ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
 +
 +      perms = file_mask_to_av(inode->i_mode, mask);
 +
 +      return inode_has_perm(cred, inode, perms, &ad);
  }
  
  static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@@ -3333,16 -3374,17 +3336,17 @@@ static int selinux_task_getioprio(struc
        return current_has_perm(p, PROCESS__GETSCHED);
  }
  
- static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim)
  {
-       struct rlimit *old_rlim = current->signal->rlim + resource;
+       struct rlimit *old_rlim = p->signal->rlim + resource;
  
        /* Control the ability to change the hard limit (whether
           lowering or raising it), so that the hard limit can
           later be used as a safe reset point for the soft limit
           upon context transitions.  See selinux_bprm_committing_creds. */
        if (old_rlim->rlim_max != new_rlim->rlim_max)
-               return current_has_perm(current, PROCESS__SETRLIMIT);
+               return current_has_perm(p, PROCESS__SETRLIMIT);
  
        return 0;
  }
@@@ -3633,54 -3675,71 +3637,54 @@@ static int selinux_skb_peerlbl_sid(stru
  }
  
  /* socket security operations */
 -static int socket_has_perm(struct task_struct *task, struct socket *sock,
 -                         u32 perms)
 +
 +static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
  {
 -      struct inode_security_struct *isec;
 -      struct common_audit_data ad;
 -      u32 sid;
 -      int err = 0;
 +      return tsec->sockcreate_sid ? : tsec->sid;
 +}
  
 -      isec = SOCK_INODE(sock)->i_security;
 +static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
 +{
 +      struct sk_security_struct *sksec = sk->sk_security;
 +      struct common_audit_data ad;
 +      u32 tsid = task_sid(task);
  
 -      if (isec->sid == SECINITSID_KERNEL)
 -              goto out;
 -      sid = task_sid(task);
 +      if (sksec->sid == SECINITSID_KERNEL)
 +              return 0;
  
        COMMON_AUDIT_DATA_INIT(&ad, NET);
 -      ad.u.net.sk = sock->sk;
 -      err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 +      ad.u.net.sk = sk;
  
 -out:
 -      return err;
 +      return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
  }
  
  static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
  {
 -      const struct cred *cred = current_cred();
 -      const struct task_security_struct *tsec = cred->security;
 -      u32 sid, newsid;
 +      const struct task_security_struct *tsec = current_security();
 +      u32 newsid;
        u16 secclass;
 -      int err = 0;
  
        if (kern)
 -              goto out;
 -
 -      sid = tsec->sid;
 -      newsid = tsec->sockcreate_sid ?: sid;
 +              return 0;
  
 +      newsid = socket_sockcreate_sid(tsec);
        secclass = socket_type_to_security_class(family, type, protocol);
 -      err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
 -
 -out:
 -      return err;
 +      return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
  }
  
  static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
  {
 -      const struct cred *cred = current_cred();
 -      const struct task_security_struct *tsec = cred->security;
 -      struct inode_security_struct *isec;
 +      const struct task_security_struct *tsec = current_security();
 +      struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
        struct sk_security_struct *sksec;
 -      u32 sid, newsid;
        int err = 0;
  
 -      sid = tsec->sid;
 -      newsid = tsec->sockcreate_sid;
 -
 -      isec = SOCK_INODE(sock)->i_security;
 -
        if (kern)
                isec->sid = SECINITSID_KERNEL;
 -      else if (newsid)
 -              isec->sid = newsid;
        else
 -              isec->sid = sid;
 +              isec->sid = socket_sockcreate_sid(tsec);
  
        isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->initialized = 1;
  
  static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
  {
 +      struct sock *sk = sock->sk;
        u16 family;
        int err;
  
 -      err = socket_has_perm(current, sock, SOCKET__BIND);
 +      err = sock_has_perm(current, sk, SOCKET__BIND);
        if (err)
                goto out;
  
         * Multiple address binding for SCTP is not supported yet: we just
         * check the first address now.
         */
 -      family = sock->sk->sk_family;
 +      family = sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
 -              struct inode_security_struct *isec;
 +              struct sk_security_struct *sksec = sk->sk_security;
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
 -              struct sock *sk = sock->sk;
                u32 sid, node_perm;
  
 -              isec = SOCK_INODE(sock)->i_security;
 -
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
                                COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
 -                              err = avc_has_perm(isec->sid, sid,
 -                                                 isec->sclass,
 +                              err = avc_has_perm(sksec->sid, sid,
 +                                                 sksec->sclass,
                                                   SOCKET__NAME_BIND, &ad);
                                if (err)
                                        goto out;
                        }
                }
  
 -              switch (isec->sclass) {
 +              switch (sksec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
                else
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
  
 -              err = avc_has_perm(isec->sid, sid,
 -                                 isec->sclass, node_perm, &ad);
 +              err = avc_has_perm(sksec->sid, sid,
 +                                 sksec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
  static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
  {
        struct sock *sk = sock->sk;
 -      struct inode_security_struct *isec;
 +      struct sk_security_struct *sksec = sk->sk_security;
        int err;
  
 -      err = socket_has_perm(current, sock, SOCKET__CONNECT);
 +      err = sock_has_perm(current, sk, SOCKET__CONNECT);
        if (err)
                return err;
  
        /*
         * If a TCP or DCCP socket, check name_connect permission for the port.
         */
 -      isec = SOCK_INODE(sock)->i_security;
 -      if (isec->sclass == SECCLASS_TCP_SOCKET ||
 -          isec->sclass == SECCLASS_DCCP_SOCKET) {
 +      if (sksec->sclass == SECCLASS_TCP_SOCKET ||
 +          sksec->sclass == SECCLASS_DCCP_SOCKET) {
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                if (err)
                        goto out;
  
 -              perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
 +              perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
  
                COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
 -              err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
 +              err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
                if (err)
                        goto out;
        }
@@@ -3851,7 -3913,7 +3855,7 @@@ out
  
  static int selinux_socket_listen(struct socket *sock, int backlog)
  {
 -      return socket_has_perm(current, sock, SOCKET__LISTEN);
 +      return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
  }
  
  static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        struct inode_security_struct *isec;
        struct inode_security_struct *newisec;
  
 -      err = socket_has_perm(current, sock, SOCKET__ACCEPT);
 +      err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
  
  static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
  {
 -      return socket_has_perm(current, sock, SOCKET__WRITE);
 +      return sock_has_perm(current, sock->sk, SOCKET__WRITE);
  }
  
  static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                                  int size, int flags)
  {
 -      return socket_has_perm(current, sock, SOCKET__READ);
 +      return sock_has_perm(current, sock->sk, SOCKET__READ);
  }
  
  static int selinux_socket_getsockname(struct socket *sock)
  {
 -      return socket_has_perm(current, sock, SOCKET__GETATTR);
 +      return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
  }
  
  static int selinux_socket_getpeername(struct socket *sock)
  {
 -      return socket_has_perm(current, sock, SOCKET__GETATTR);
 +      return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
  }
  
  static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
  {
        int err;
  
 -      err = socket_has_perm(current, sock, SOCKET__SETOPT);
 +      err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
        if (err)
                return err;
  
  static int selinux_socket_getsockopt(struct socket *sock, int level,
                                     int optname)
  {
 -      return socket_has_perm(current, sock, SOCKET__GETOPT);
 +      return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
  }
  
  static int selinux_socket_shutdown(struct socket *sock, int how)
  {
 -      return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
 +      return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
  }
  
  static int selinux_socket_unix_stream_connect(struct socket *sock,
                                              struct socket *other,
                                              struct sock *newsk)
  {
 -      struct sk_security_struct *sksec;
 -      struct inode_security_struct *isec;
 -      struct inode_security_struct *other_isec;
 +      struct sk_security_struct *sksec_sock = sock->sk->sk_security;
 +      struct sk_security_struct *sksec_other = other->sk->sk_security;
 +      struct sk_security_struct *sksec_new = newsk->sk_security;
        struct common_audit_data ad;
        int err;
  
 -      isec = SOCK_INODE(sock)->i_security;
 -      other_isec = SOCK_INODE(other)->i_security;
 -
        COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
  
 -      err = avc_has_perm(isec->sid, other_isec->sid,
 -                         isec->sclass,
 +      err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
 +                         sksec_other->sclass,
                           UNIX_STREAM_SOCKET__CONNECTTO, &ad);
        if (err)
                return err;
  
 -      /* connecting socket */
 -      sksec = sock->sk->sk_security;
 -      sksec->peer_sid = other_isec->sid;
 -
        /* server child socket */
 -      sksec = newsk->sk_security;
 -      sksec->peer_sid = isec->sid;
 -      err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
 +      sksec_new->peer_sid = sksec_sock->sid;
 +      err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
 +                                  &sksec_new->sid);
 +      if (err)
 +              return err;
  
 -      return err;
 +      /* connecting socket */
 +      sksec_sock->peer_sid = sksec_new->sid;
 +
 +      return 0;
  }
  
  static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
  {
 -      struct inode_security_struct *isec;
 -      struct inode_security_struct *other_isec;
 +      struct sk_security_struct *ssec = sock->sk->sk_security;
 +      struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
 -      int err;
 -
 -      isec = SOCK_INODE(sock)->i_security;
 -      other_isec = SOCK_INODE(other)->i_security;
  
        COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
  
 -      err = avc_has_perm(isec->sid, other_isec->sid,
 -                         isec->sclass, SOCKET__SENDTO, &ad);
 -      if (err)
 -              return err;
 -
 -      return 0;
 +      return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
 +                          &ad);
  }
  
  static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
@@@ -4100,18 -4172,26 +4104,18 @@@ static int selinux_socket_getpeersec_st
        int err = 0;
        char *scontext;
        u32 scontext_len;
 -      struct sk_security_struct *sksec;
 -      struct inode_security_struct *isec;
 +      struct sk_security_struct *sksec = sock->sk->sk_security;
        u32 peer_sid = SECSID_NULL;
  
 -      isec = SOCK_INODE(sock)->i_security;
 -
 -      if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
 -          isec->sclass == SECCLASS_TCP_SOCKET) {
 -              sksec = sock->sk->sk_security;
 +      if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
 +          sksec->sclass == SECCLASS_TCP_SOCKET)
                peer_sid = sksec->peer_sid;
 -      }
 -      if (peer_sid == SECSID_NULL) {
 -              err = -ENOPROTOOPT;
 -              goto out;
 -      }
 +      if (peer_sid == SECSID_NULL)
 +              return -ENOPROTOOPT;
  
        err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
 -
        if (err)
 -              goto out;
 +              return err;
  
        if (scontext_len > len) {
                err = -ERANGE;
  out_len:
        if (put_user(scontext_len, optlen))
                err = -EFAULT;
 -
        kfree(scontext);
 -out:
        return err;
  }
  
  
  static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
  {
 -      return sk_alloc_security(sk, family, priority);
 +      struct sk_security_struct *sksec;
 +
 +      sksec = kzalloc(sizeof(*sksec), priority);
 +      if (!sksec)
 +              return -ENOMEM;
 +
 +      sksec->peer_sid = SECINITSID_UNLABELED;
 +      sksec->sid = SECINITSID_UNLABELED;
 +      selinux_netlbl_sk_security_reset(sksec);
 +      sk->sk_security = sksec;
 +
 +      return 0;
  }
  
  static void selinux_sk_free_security(struct sock *sk)
  {
 -      sk_free_security(sk);
 +      struct sk_security_struct *sksec = sk->sk_security;
 +
 +      sk->sk_security = NULL;
 +      selinux_netlbl_sk_security_free(sksec);
 +      kfree(sksec);
  }
  
  static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@@ -4336,7 -4403,8 +4340,7 @@@ static int selinux_nlmsg_perm(struct so
        int err = 0;
        u32 perm;
        struct nlmsghdr *nlh;
 -      struct socket *sock = sk->sk_socket;
 -      struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
 +      struct sk_security_struct *sksec = sk->sk_security;
  
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
        }
        nlh = nlmsg_hdr(skb);
  
 -      err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
 +      err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
                        audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
 -                                nlh->nlmsg_type, isec->sclass);
 +                                nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
                goto out;
        }
  
 -      err = socket_has_perm(current, sock, perm);
 +      err = sock_has_perm(current, sk, perm);
  out:
        return err;
  }