1/* uaccess.c: userspace access functions 2 * 3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/mm.h> 13#include <linux/module.h> 14#include <asm/uaccess.h> 15 16/*****************************************************************************/ 17/* 18 * copy a null terminated string from userspace 19 */ 20long strncpy_from_user(char *dst, const char __user *src, long count) 21{ 22 unsigned long max; 23 char *p, ch; 24 long err = -EFAULT; 25 26 if (count < 0) 27 BUG(); 28 29 p = dst; 30 31#ifndef CONFIG_MMU 32 if ((unsigned long) src < memory_start) 33 goto error; 34#endif 35 36 if ((unsigned long) src >= get_addr_limit()) 37 goto error; 38 39 max = get_addr_limit() - (unsigned long) src; 40 if ((unsigned long) count > max) { 41 memset(dst + max, 0, count - max); 42 count = max; 43 } 44 45 err = 0; 46 for (; count > 0; count--, p++, src++) { 47 __get_user_asm(err, ch, src, "ub", "=r"); 48 if (err < 0) 49 goto error; 50 if (!ch) 51 break; 52 *p = ch; 53 } 54 55 err = p - dst; /* return length excluding NUL */ 56 57 error: 58 if (count > 0) 59 memset(p, 0, count); /* clear remainder of buffer [security] */ 60 61 return err; 62 63} /* end strncpy_from_user() */ 64 65EXPORT_SYMBOL(strncpy_from_user); 66 67/*****************************************************************************/ 68/* 69 * Return the size of a string (including the ending 0) 70 * 71 * Return 0 on exception, a value greater than N if too long 72 */ 73long strnlen_user(const char __user *src, long count) 74{ 75 const char __user *p; 76 long err = 0; 77 char ch; 78 79 if (count < 0) 80 BUG(); 81 82#ifndef CONFIG_MMU 83 if ((unsigned long) src < memory_start) 84 return 0; 85#endif 86 87 if ((unsigned long) src >= get_addr_limit()) 88 return 0; 89 90 for (p = src; count > 0; count--, p++) { 91 __get_user_asm(err, ch, p, "ub", "=r"); 92 if (err < 0) 93 return 0; 94 if (!ch) 95 break; 96 } 97 98 return p - src + 1; /* return length including NUL */ 99 100} /* end strnlen_user() */ 101 102EXPORT_SYMBOL(strnlen_user); 103