Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Use the new generic strncpy_from_user() and strnlen_user()

This is much the same as for SPARC except that we can do the find_zero()
function more efficiently using the count-leading-zeroes instructions.
Tested on 32-bit and 64-bit PowerPC.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Paul Mackerras and committed by
Linus Torvalds
1629372c 69ea6405

+48 -83
+2
arch/powerpc/Kconfig
··· 135 135 select GENERIC_CMOS_UPDATE 136 136 select GENERIC_TIME_VSYSCALL 137 137 select GENERIC_CLOCKEVENTS 138 + select GENERIC_STRNCPY_FROM_USER 139 + select GENERIC_STRNLEN_USER 138 140 139 141 config EARLY_PRINTK 140 142 bool
+5 -36
arch/powerpc/include/asm/uaccess.h
··· 40 40 41 41 #define segment_eq(a, b) ((a).seg == (b).seg) 42 42 43 + #define user_addr_max() (get_fs().seg) 44 + 43 45 #ifdef __powerpc64__ 44 46 /* 45 47 * This check is sufficient because there is a large enough ··· 455 453 return size; 456 454 } 457 455 458 - extern int __strncpy_from_user(char *dst, const char __user *src, long count); 459 - 460 - static inline long strncpy_from_user(char *dst, const char __user *src, 461 - long count) 462 - { 463 - might_sleep(); 464 - if (likely(access_ok(VERIFY_READ, src, 1))) 465 - return __strncpy_from_user(dst, src, count); 466 - return -EFAULT; 467 - } 468 - 469 - /* 470 - * Return the size of a string (including the ending 0) 471 - * 472 - * Return 0 for error 473 - */ 474 - extern int __strnlen_user(const char __user *str, long len, unsigned long top); 475 - 476 - /* 477 - * Returns the length of the string at str (including the null byte), 478 - * or 0 if we hit a page we can't access, 479 - * or something > len if we didn't find a null byte. 480 - * 481 - * The `top' parameter to __strnlen_user is to make sure that 482 - * we can never overflow from the user area into kernel space. 483 - */ 484 - static inline int strnlen_user(const char __user *str, long len) 485 - { 486 - unsigned long top = current->thread.fs.seg; 487 - 488 - if ((unsigned long)str > top) 489 - return 0; 490 - return __strnlen_user(str, len, top); 491 - } 492 - 493 - #define strlen_user(str) strnlen_user((str), 0x7ffffffe) 456 + extern long strncpy_from_user(char *dst, const char __user *src, long count); 457 + extern __must_check long strlen_user(const char __user *str); 458 + extern __must_check long strnlen_user(const char __user *str, long n); 494 459 495 460 #endif /* __ASSEMBLY__ */ 496 461 #endif /* __KERNEL__ */
+41
arch/powerpc/include/asm/word-at-a-time.h
··· 1 + #ifndef _ASM_WORD_AT_A_TIME_H 2 + #define _ASM_WORD_AT_A_TIME_H 3 + 4 + /* 5 + * Word-at-a-time interfaces for PowerPC. 6 + */ 7 + 8 + #include <linux/kernel.h> 9 + #include <asm/asm-compat.h> 10 + 11 + struct word_at_a_time { 12 + const unsigned long high_bits, low_bits; 13 + }; 14 + 15 + #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) } 16 + 17 + /* Bit set in the bytes that have a zero */ 18 + static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c) 19 + { 20 + unsigned long mask = (val & c->low_bits) + c->low_bits; 21 + return ~(mask | rhs); 22 + } 23 + 24 + #define create_zero_mask(mask) (mask) 25 + 26 + static inline long find_zero(unsigned long mask) 27 + { 28 + long leading_zero_bits; 29 + 30 + asm (PPC_CNTLZL "%0,%1" : "=r" (leading_zero_bits) : "r" (mask)); 31 + return leading_zero_bits >> 3; 32 + } 33 + 34 + static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) 35 + { 36 + unsigned long rhs = val | c->low_bits; 37 + *data = rhs; 38 + return (val + c->high_bits) & ~rhs; 39 + } 40 + 41 + #endif /* _ASM_WORD_AT_A_TIME_H */
-2
arch/powerpc/kernel/ppc_ksyms.c
··· 85 85 86 86 EXPORT_SYMBOL(__copy_tofrom_user); 87 87 EXPORT_SYMBOL(__clear_user); 88 - EXPORT_SYMBOL(__strncpy_from_user); 89 - EXPORT_SYMBOL(__strnlen_user); 90 88 EXPORT_SYMBOL(copy_page); 91 89 92 90 #if defined(CONFIG_PCI) && defined(CONFIG_PPC32)
-45
arch/powerpc/lib/string.S
··· 160 160 PPC_LONG 1b,91b 161 161 PPC_LONG 8b,92b 162 162 .text 163 - 164 - _GLOBAL(__strncpy_from_user) 165 - addi r6,r3,-1 166 - addi r4,r4,-1 167 - cmpwi 0,r5,0 168 - beq 2f 169 - mtctr r5 170 - 1: lbzu r0,1(r4) 171 - cmpwi 0,r0,0 172 - stbu r0,1(r6) 173 - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ 174 - beq 3f 175 - 2: addi r6,r6,1 176 - 3: subf r3,r3,r6 177 - blr 178 - 99: li r3,-EFAULT 179 - blr 180 - 181 - .section __ex_table,"a" 182 - PPC_LONG 1b,99b 183 - .text 184 - 185 - /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ 186 - _GLOBAL(__strnlen_user) 187 - addi r7,r3,-1 188 - subf r6,r7,r5 /* top+1 - str */ 189 - cmplw 0,r4,r6 190 - bge 0f 191 - mr r6,r4 192 - 0: mtctr r6 /* ctr = min(len, top - str) */ 193 - 1: lbzu r0,1(r7) /* get next byte */ 194 - cmpwi 0,r0,0 195 - bdnzf 2,1b /* loop if --ctr != 0 && byte != 0 */ 196 - addi r7,r7,1 197 - subf r3,r3,r7 /* number of bytes we have looked at */ 198 - beqlr /* return if we found a 0 byte */ 199 - cmpw 0,r3,r4 /* did we look at all len bytes? */ 200 - blt 99f /* if not, must have hit top */ 201 - addi r3,r4,1 /* return len + 1 to indicate no null found */ 202 - blr 203 - 99: li r3,0 /* bad address, return 0 */ 204 - blr 205 - 206 - .section __ex_table,"a" 207 - PPC_LONG 1b,99b