| /* 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); |