binfmt_flat: do not stop relocating GOT entries prematurely on riscv
[sfrench/cifs-2.6.git] / fs / binfmt_flat.c
index 6268981500112fd3cc20350649ceb9c4c878d3b5..dca0b6875f9c3c1961b14524362fdb36ffa3788e 100644 (file)
@@ -440,6 +440,30 @@ static void old_reloc(unsigned long rl)
 
 /****************************************************************************/
 
+static inline u32 __user *skip_got_header(u32 __user *rp)
+{
+       if (IS_ENABLED(CONFIG_RISCV)) {
+               /*
+                * RISC-V has a 16 byte GOT PLT header for elf64-riscv
+                * and 8 byte GOT PLT header for elf32-riscv.
+                * Skip the whole GOT PLT header, since it is reserved
+                * for the dynamic linker (ld.so).
+                */
+               u32 rp_val0, rp_val1;
+
+               if (get_user(rp_val0, rp))
+                       return rp;
+               if (get_user(rp_val1, rp + 1))
+                       return rp;
+
+               if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff)
+                       rp += 4;
+               else if (rp_val0 == 0xffffffff)
+                       rp += 2;
+       }
+       return rp;
+}
+
 static int load_flat_file(struct linux_binprm *bprm,
                struct lib_info *libinfo, int id, unsigned long *extra_stack)
 {
@@ -789,7 +813,8 @@ static int load_flat_file(struct linux_binprm *bprm,
         * image.
         */
        if (flags & FLAT_FLAG_GOTPIC) {
-               for (rp = (u32 __user *)datapos; ; rp++) {
+               rp = skip_got_header((u32 __user *) datapos);
+               for (; ; rp++) {
                        u32 addr, rp_val;
                        if (get_user(rp_val, rp))
                                return -EFAULT;