drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / exec.c
index 8500ffa8822a6347d153704d7b977cc5fc9b7bc9..4352a8b4610b56bd6350996617049e241179038a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -19,7 +19,7 @@
  * current->executable is only used by the procfs.  This allows a dispatch
  * table to check for several different types  of binary formats.  We keep
  * trying until we recognize the file or we run out of supported binary
- * formats. 
+ * formats.
  */
 
 #include <linux/slab.h>
@@ -196,8 +196,26 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 
        if (write) {
                unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+               unsigned long ptr_size;
                struct rlimit *rlim;
 
+               /*
+                * Since the stack will hold pointers to the strings, we
+                * must account for them as well.
+                *
+                * The size calculation is the entire vma while each arg page is
+                * built, so each time we get here it's calculating how far it
+                * is currently (rather than each call being just the newly
+                * added size from the arg page).  As a result, we need to
+                * always add the entire size of the pointers, so that on the
+                * last call to get_arg_page() we'll actually have the entire
+                * correct size.
+                */
+               ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
+               if (ptr_size > ULONG_MAX - size)
+                       goto fail;
+               size += ptr_size;
+
                acct_arg_size(bprm, size / PAGE_SIZE);
 
                /*
@@ -215,13 +233,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
                 *    to work from.
                 */
                rlim = current->signal->rlim;
-               if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
-                       put_page(page);
-                       return NULL;
-               }
+               if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4)
+                       goto fail;
        }
 
        return page;
+
+fail:
+       put_page(page);
+       return NULL;
 }
 
 static void put_arg_page(struct page *page)
@@ -1091,6 +1111,13 @@ int flush_old_exec(struct linux_binprm * bprm)
        flush_thread();
        current->personality &= ~bprm->per_clear;
 
+       /*
+        * We have to apply CLOEXEC before we change whether the process is
+        * dumpable (in setup_new_exec) to avoid a race with a process in userspace
+        * trying to access the should-be-closed file descriptors of a process
+        * undergoing exec(2).
+        */
+       do_close_on_exec(current->files);
        return 0;
 
 out:
@@ -1141,7 +1168,6 @@ void setup_new_exec(struct linux_binprm * bprm)
        current->self_exec_id++;
                        
        flush_signal_handlers(current, 0);
-       do_close_on_exec(current->files);
 }
 EXPORT_SYMBOL(setup_new_exec);
 
@@ -1279,9 +1305,6 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                return;
 
-       if (current->no_new_privs)
-               return;
-
        inode = file_inode(bprm->file);
        mode = ACCESS_ONCE(inode->i_mode);
        if (!(mode & (S_ISUID|S_ISGID)))
@@ -1484,6 +1507,7 @@ static int do_execve_common(const char *filename,
        bool clear_in_exec;
        int retval;
        const struct cred *cred = current_cred();
+       bool is_su;
 
        /*
         * We move the actual failure in case of RLIMIT_NPROC excess from
@@ -1560,10 +1584,18 @@ static int do_execve_common(const char *filename,
        if (retval < 0)
                goto out;
 
+       /* search_binary_handler can release file and it may be freed */
+       is_su = d_is_su(file->f_dentry);
+
        retval = search_binary_handler(bprm);
        if (retval < 0)
                goto out;
 
+       if (is_su && capable(CAP_SYS_ADMIN)) {
+               current->flags |= PF_SU;
+               su_exec();
+       }
+
        /* execve succeeded */
        current->fs->in_exec = 0;
        current->in_execve = 0;