|  | /* uaccess.c: userspace access functions | 
|  | * | 
|  | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 
|  | * Written by David Howells (dhowells@redhat.com) | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License | 
|  | * as published by the Free Software Foundation; either version | 
|  | * 2 of the License, or (at your option) any later version. | 
|  | */ | 
|  |  | 
|  | #include <linux/mm.h> | 
|  | #include <linux/module.h> | 
|  | #include <asm/uaccess.h> | 
|  |  | 
|  | /*****************************************************************************/ | 
|  | /* | 
|  | * copy a null terminated string from userspace | 
|  | */ | 
|  | long strncpy_from_user(char *dst, const char __user *src, long count) | 
|  | { | 
|  | unsigned long max; | 
|  | char *p, ch; | 
|  | long err = -EFAULT; | 
|  |  | 
|  | if (count < 0) | 
|  | BUG(); | 
|  |  | 
|  | p = dst; | 
|  |  | 
|  | #ifndef CONFIG_MMU | 
|  | if ((unsigned long) src < memory_start) | 
|  | goto error; | 
|  | #endif | 
|  |  | 
|  | if ((unsigned long) src >= get_addr_limit()) | 
|  | goto error; | 
|  |  | 
|  | max = get_addr_limit() - (unsigned long) src; | 
|  | if ((unsigned long) count > max) { | 
|  | memset(dst + max, 0, count - max); | 
|  | count = max; | 
|  | } | 
|  |  | 
|  | err = 0; | 
|  | for (; count > 0; count--, p++, src++) { | 
|  | __get_user_asm(err, ch, src, "ub", "=r"); | 
|  | if (err < 0) | 
|  | goto error; | 
|  | if (!ch) | 
|  | break; | 
|  | *p = ch; | 
|  | } | 
|  |  | 
|  | err = p - dst; /* return length excluding NUL */ | 
|  |  | 
|  | error: | 
|  | if (count > 0) | 
|  | memset(p, 0, count); /* clear remainder of buffer [security] */ | 
|  |  | 
|  | return err; | 
|  |  | 
|  | } /* end strncpy_from_user() */ | 
|  |  | 
|  | EXPORT_SYMBOL(strncpy_from_user); | 
|  |  | 
|  | /*****************************************************************************/ | 
|  | /* | 
|  | * Return the size of a string (including the ending 0) | 
|  | * | 
|  | * Return 0 on exception, a value greater than N if too long | 
|  | */ | 
|  | long strnlen_user(const char __user *src, long count) | 
|  | { | 
|  | const char __user *p; | 
|  | long err = 0; | 
|  | char ch; | 
|  |  | 
|  | if (count < 0) | 
|  | BUG(); | 
|  |  | 
|  | #ifndef CONFIG_MMU | 
|  | if ((unsigned long) src < memory_start) | 
|  | return 0; | 
|  | #endif | 
|  |  | 
|  | if ((unsigned long) src >= get_addr_limit()) | 
|  | return 0; | 
|  |  | 
|  | for (p = src; count > 0; count--, p++) { | 
|  | __get_user_asm(err, ch, p, "ub", "=r"); | 
|  | if (err < 0) | 
|  | return 0; | 
|  | if (!ch) | 
|  | break; | 
|  | } | 
|  |  | 
|  | return p - src + 1; /* return length including NUL */ | 
|  |  | 
|  | } /* end strnlen_user() */ | 
|  |  | 
|  | EXPORT_SYMBOL(strnlen_user); |