1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | |
3 | /* |
4 | * PARISC specific syscalls |
5 | * |
6 | * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org> |
7 | * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org> |
8 | * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org> |
9 | * Copyright (C) 1999-2020 Helge Deller <deller@gmx.de> |
10 | */ |
11 | |
12 | #include <linux/uaccess.h> |
13 | #include <asm/elf.h> |
14 | #include <linux/file.h> |
15 | #include <linux/fs.h> |
16 | #include <linux/linkage.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/mman.h> |
19 | #include <linux/sched/signal.h> |
20 | #include <linux/sched/mm.h> |
21 | #include <linux/shm.h> |
22 | #include <linux/syscalls.h> |
23 | #include <linux/utsname.h> |
24 | #include <linux/personality.h> |
25 | #include <linux/random.h> |
26 | #include <linux/compat.h> |
27 | #include <linux/elf-randomize.h> |
28 | |
29 | /* |
30 | * Construct an artificial page offset for the mapping based on the physical |
31 | * address of the kernel file mapping variable. |
32 | */ |
33 | #define GET_FILP_PGOFF(filp) \ |
34 | (filp ? (((unsigned long) filp->f_mapping) >> 8) \ |
35 | & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL) |
36 | |
37 | static unsigned long shared_align_offset(unsigned long filp_pgoff, |
38 | unsigned long pgoff) |
39 | { |
40 | return (filp_pgoff + pgoff) << PAGE_SHIFT; |
41 | } |
42 | |
43 | static inline unsigned long COLOR_ALIGN(unsigned long addr, |
44 | unsigned long filp_pgoff, unsigned long pgoff) |
45 | { |
46 | unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1); |
47 | unsigned long off = (SHM_COLOUR-1) & |
48 | shared_align_offset(filp_pgoff, pgoff); |
49 | return base + off; |
50 | } |
51 | |
52 | |
53 | #define STACK_SIZE_DEFAULT (USER_WIDE_MODE \ |
54 | ? (1 << 30) /* 1 GB */ \ |
55 | : (CONFIG_STACK_MAX_DEFAULT_SIZE_MB*1024*1024)) |
56 | |
57 | unsigned long calc_max_stack_size(unsigned long stack_max) |
58 | { |
59 | #ifdef CONFIG_COMPAT |
60 | if (!USER_WIDE_MODE && (stack_max == COMPAT_RLIM_INFINITY)) |
61 | stack_max = STACK_SIZE_DEFAULT; |
62 | else |
63 | #endif |
64 | if (stack_max == RLIM_INFINITY) |
65 | stack_max = STACK_SIZE_DEFAULT; |
66 | |
67 | return stack_max; |
68 | } |
69 | |
70 | |
71 | /* |
72 | * Top of mmap area (just below the process stack). |
73 | */ |
74 | |
75 | /* |
76 | * When called from arch_get_unmapped_area(), rlim_stack will be NULL, |
77 | * indicating that "current" should be used instead of a passed-in |
78 | * value from the exec bprm as done with arch_pick_mmap_layout(). |
79 | */ |
80 | unsigned long mmap_upper_limit(struct rlimit *rlim_stack) |
81 | { |
82 | unsigned long stack_base; |
83 | |
84 | /* Limit stack size - see setup_arg_pages() in fs/exec.c */ |
85 | stack_base = rlim_stack ? rlim_stack->rlim_max |
86 | : rlimit_max(RLIMIT_STACK); |
87 | |
88 | stack_base = calc_max_stack_size(stack_max: stack_base); |
89 | |
90 | /* Add space for stack randomization. */ |
91 | if (current->flags & PF_RANDOMIZE) |
92 | stack_base += (STACK_RND_MASK << PAGE_SHIFT); |
93 | |
94 | return PAGE_ALIGN(STACK_TOP - stack_base); |
95 | } |
96 | |
97 | enum mmap_allocation_direction {UP, DOWN}; |
98 | |
99 | static unsigned long arch_get_unmapped_area_common(struct file *filp, |
100 | unsigned long addr, unsigned long len, unsigned long pgoff, |
101 | unsigned long flags, enum mmap_allocation_direction dir) |
102 | { |
103 | struct mm_struct *mm = current->mm; |
104 | struct vm_area_struct *vma, *prev; |
105 | unsigned long filp_pgoff; |
106 | int do_color_align; |
107 | struct vm_unmapped_area_info info; |
108 | |
109 | if (unlikely(len > TASK_SIZE)) |
110 | return -ENOMEM; |
111 | |
112 | do_color_align = 0; |
113 | if (filp || (flags & MAP_SHARED)) |
114 | do_color_align = 1; |
115 | filp_pgoff = GET_FILP_PGOFF(filp); |
116 | |
117 | if (flags & MAP_FIXED) { |
118 | /* Even MAP_FIXED mappings must reside within TASK_SIZE */ |
119 | if (TASK_SIZE - len < addr) |
120 | return -EINVAL; |
121 | |
122 | if ((flags & MAP_SHARED) && filp && |
123 | (addr - shared_align_offset(filp_pgoff, pgoff)) |
124 | & (SHM_COLOUR - 1)) |
125 | return -EINVAL; |
126 | return addr; |
127 | } |
128 | |
129 | if (addr) { |
130 | if (do_color_align) |
131 | addr = COLOR_ALIGN(addr, filp_pgoff, pgoff); |
132 | else |
133 | addr = PAGE_ALIGN(addr); |
134 | |
135 | vma = find_vma_prev(mm, addr, pprev: &prev); |
136 | if (TASK_SIZE - len >= addr && |
137 | (!vma || addr + len <= vm_start_gap(vma)) && |
138 | (!prev || addr >= vm_end_gap(vma: prev))) |
139 | return addr; |
140 | } |
141 | |
142 | info.length = len; |
143 | info.align_mask = do_color_align ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; |
144 | info.align_offset = shared_align_offset(filp_pgoff, pgoff); |
145 | |
146 | if (dir == DOWN) { |
147 | info.flags = VM_UNMAPPED_AREA_TOPDOWN; |
148 | info.low_limit = PAGE_SIZE; |
149 | info.high_limit = mm->mmap_base; |
150 | addr = vm_unmapped_area(info: &info); |
151 | if (!(addr & ~PAGE_MASK)) |
152 | return addr; |
153 | VM_BUG_ON(addr != -ENOMEM); |
154 | |
155 | /* |
156 | * A failed mmap() very likely causes application failure, |
157 | * so fall back to the bottom-up function here. This scenario |
158 | * can happen with large stack limits and large mmap() |
159 | * allocations. |
160 | */ |
161 | } |
162 | |
163 | info.flags = 0; |
164 | info.low_limit = mm->mmap_base; |
165 | info.high_limit = mmap_upper_limit(NULL); |
166 | return vm_unmapped_area(info: &info); |
167 | } |
168 | |
169 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, |
170 | unsigned long len, unsigned long pgoff, unsigned long flags) |
171 | { |
172 | return arch_get_unmapped_area_common(filp, |
173 | addr, len, pgoff, flags, dir: UP); |
174 | } |
175 | |
176 | unsigned long arch_get_unmapped_area_topdown(struct file *filp, |
177 | unsigned long addr, unsigned long len, unsigned long pgoff, |
178 | unsigned long flags) |
179 | { |
180 | return arch_get_unmapped_area_common(filp, |
181 | addr, len, pgoff, flags, dir: DOWN); |
182 | } |
183 | |
184 | asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, |
185 | unsigned long prot, unsigned long flags, unsigned long fd, |
186 | unsigned long pgoff) |
187 | { |
188 | /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE |
189 | we have. */ |
190 | return ksys_mmap_pgoff(addr, len, prot, flags, fd, |
191 | pgoff: pgoff >> (PAGE_SHIFT - 12)); |
192 | } |
193 | |
194 | asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, |
195 | unsigned long prot, unsigned long flags, unsigned long fd, |
196 | unsigned long offset) |
197 | { |
198 | if (!(offset & ~PAGE_MASK)) { |
199 | return ksys_mmap_pgoff(addr, len, prot, flags, fd, |
200 | pgoff: offset >> PAGE_SHIFT); |
201 | } else { |
202 | return -EINVAL; |
203 | } |
204 | } |
205 | |
206 | /* Fucking broken ABI */ |
207 | |
208 | #ifdef CONFIG_64BIT |
209 | asmlinkage long parisc_truncate64(const char __user * path, |
210 | unsigned int high, unsigned int low) |
211 | { |
212 | return ksys_truncate(pathname: path, length: (long)high << 32 | low); |
213 | } |
214 | |
215 | asmlinkage long parisc_ftruncate64(unsigned int fd, |
216 | unsigned int high, unsigned int low) |
217 | { |
218 | return ksys_ftruncate(fd, length: (long)high << 32 | low); |
219 | } |
220 | |
221 | /* stubs for the benefit of the syscall_table since truncate64 and truncate |
222 | * are identical on LP64 */ |
223 | asmlinkage long sys_truncate64(const char __user * path, unsigned long length) |
224 | { |
225 | return ksys_truncate(pathname: path, length); |
226 | } |
227 | asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length) |
228 | { |
229 | return ksys_ftruncate(fd, length); |
230 | } |
231 | asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) |
232 | { |
233 | return sys_fcntl(fd, cmd, arg); |
234 | } |
235 | #else |
236 | |
237 | asmlinkage long parisc_truncate64(const char __user * path, |
238 | unsigned int high, unsigned int low) |
239 | { |
240 | return ksys_truncate(path, (loff_t)high << 32 | low); |
241 | } |
242 | |
243 | asmlinkage long parisc_ftruncate64(unsigned int fd, |
244 | unsigned int high, unsigned int low) |
245 | { |
246 | return sys_ftruncate64(fd, (loff_t)high << 32 | low); |
247 | } |
248 | #endif |
249 | |
250 | asmlinkage ssize_t parisc_pread64(unsigned int fd, char __user *buf, size_t count, |
251 | unsigned int high, unsigned int low) |
252 | { |
253 | return ksys_pread64(fd, buf, count, pos: (loff_t)high << 32 | low); |
254 | } |
255 | |
256 | asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char __user *buf, |
257 | size_t count, unsigned int high, unsigned int low) |
258 | { |
259 | return ksys_pwrite64(fd, buf, count, pos: (loff_t)high << 32 | low); |
260 | } |
261 | |
262 | asmlinkage ssize_t parisc_readahead(int fd, unsigned int high, unsigned int low, |
263 | size_t count) |
264 | { |
265 | return ksys_readahead(fd, offset: (loff_t)high << 32 | low, count); |
266 | } |
267 | |
268 | asmlinkage long parisc_fadvise64_64(int fd, |
269 | unsigned int high_off, unsigned int low_off, |
270 | unsigned int high_len, unsigned int low_len, int advice) |
271 | { |
272 | return ksys_fadvise64_64(fd, offset: (loff_t)high_off << 32 | low_off, |
273 | len: (loff_t)high_len << 32 | low_len, advice); |
274 | } |
275 | |
276 | asmlinkage long parisc_sync_file_range(int fd, |
277 | u32 hi_off, u32 lo_off, u32 hi_nbytes, u32 lo_nbytes, |
278 | unsigned int flags) |
279 | { |
280 | return ksys_sync_file_range(fd, offset: (loff_t)hi_off << 32 | lo_off, |
281 | nbytes: (loff_t)hi_nbytes << 32 | lo_nbytes, flags); |
282 | } |
283 | |
284 | asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo, |
285 | u32 lenhi, u32 lenlo) |
286 | { |
287 | return ksys_fallocate(fd, mode, offset: ((u64)offhi << 32) | offlo, |
288 | len: ((u64)lenhi << 32) | lenlo); |
289 | } |
290 | |
291 | asmlinkage long parisc_personality(unsigned long personality) |
292 | { |
293 | long err; |
294 | |
295 | if (personality(current->personality) == PER_LINUX32 |
296 | && personality(personality) == PER_LINUX) |
297 | personality = (personality & ~PER_MASK) | PER_LINUX32; |
298 | |
299 | err = sys_personality(personality); |
300 | if (personality(err) == PER_LINUX32) |
301 | err = (err & ~PER_MASK) | PER_LINUX; |
302 | |
303 | return err; |
304 | } |
305 | |
306 | /* |
307 | * Up to kernel v5.9 we defined O_NONBLOCK as 000200004, |
308 | * since then O_NONBLOCK is defined as 000200000. |
309 | * |
310 | * The following wrapper functions mask out the old |
311 | * O_NDELAY bit from calls which use O_NONBLOCK. |
312 | * |
313 | * XXX: Remove those in year 2022 (or later)? |
314 | */ |
315 | |
316 | #define O_NONBLOCK_OLD 000200004 |
317 | #define O_NONBLOCK_MASK_OUT (O_NONBLOCK_OLD & ~O_NONBLOCK) |
318 | |
319 | static int FIX_O_NONBLOCK(int flags) |
320 | { |
321 | if ((flags & O_NONBLOCK_MASK_OUT) && |
322 | !test_thread_flag(TIF_NONBLOCK_WARNING)) { |
323 | set_thread_flag(TIF_NONBLOCK_WARNING); |
324 | pr_warn("%s(%d) uses a deprecated O_NONBLOCK value." |
325 | " Please recompile with newer glibc.\n" , |
326 | current->comm, current->pid); |
327 | } |
328 | return flags & ~O_NONBLOCK_MASK_OUT; |
329 | } |
330 | |
331 | asmlinkage long parisc_timerfd_create(int clockid, int flags) |
332 | { |
333 | flags = FIX_O_NONBLOCK(flags); |
334 | return sys_timerfd_create(clockid, flags); |
335 | } |
336 | |
337 | asmlinkage long parisc_signalfd4(int ufd, sigset_t __user *user_mask, |
338 | size_t sizemask, int flags) |
339 | { |
340 | flags = FIX_O_NONBLOCK(flags); |
341 | return sys_signalfd4(ufd, user_mask, sizemask, flags); |
342 | } |
343 | |
344 | #ifdef CONFIG_COMPAT |
345 | asmlinkage long parisc_compat_signalfd4(int ufd, |
346 | compat_sigset_t __user *user_mask, |
347 | compat_size_t sizemask, int flags) |
348 | { |
349 | flags = FIX_O_NONBLOCK(flags); |
350 | return compat_sys_signalfd4(ufd, user_mask, sizemask, flags); |
351 | } |
352 | #endif |
353 | |
354 | asmlinkage long parisc_eventfd2(unsigned int count, int flags) |
355 | { |
356 | flags = FIX_O_NONBLOCK(flags); |
357 | return sys_eventfd2(count, flags); |
358 | } |
359 | |
360 | asmlinkage long parisc_userfaultfd(int flags) |
361 | { |
362 | flags = FIX_O_NONBLOCK(flags); |
363 | return sys_userfaultfd(flags); |
364 | } |
365 | |
366 | asmlinkage long parisc_pipe2(int __user *fildes, int flags) |
367 | { |
368 | flags = FIX_O_NONBLOCK(flags); |
369 | return sys_pipe2(fildes, flags); |
370 | } |
371 | |
372 | asmlinkage long parisc_inotify_init1(int flags) |
373 | { |
374 | flags = FIX_O_NONBLOCK(flags); |
375 | return sys_inotify_init1(flags); |
376 | } |
377 | |
378 | /* |
379 | * madvise() wrapper |
380 | * |
381 | * Up to kernel v6.1 parisc has different values than all other |
382 | * platforms for the MADV_xxx flags listed below. |
383 | * To keep binary compatibility with existing userspace programs |
384 | * translate the former values to the new values. |
385 | * |
386 | * XXX: Remove this wrapper in year 2025 (or later) |
387 | */ |
388 | |
389 | asmlinkage notrace long parisc_madvise(unsigned long start, size_t len_in, int behavior) |
390 | { |
391 | switch (behavior) { |
392 | case 65: behavior = MADV_MERGEABLE; break; |
393 | case 66: behavior = MADV_UNMERGEABLE; break; |
394 | case 67: behavior = MADV_HUGEPAGE; break; |
395 | case 68: behavior = MADV_NOHUGEPAGE; break; |
396 | case 69: behavior = MADV_DONTDUMP; break; |
397 | case 70: behavior = MADV_DODUMP; break; |
398 | case 71: behavior = MADV_WIPEONFORK; break; |
399 | case 72: behavior = MADV_KEEPONFORK; break; |
400 | case 73: behavior = MADV_COLLAPSE; break; |
401 | } |
402 | |
403 | return sys_madvise(start, len_in, behavior); |
404 | } |
405 | |