/** * strlen_user: - Get the size of a user string INCLUDING final NUL. * @str: The string to measure. * * Context: User context only. This function may sleep. * * Get the size of a NUL-terminated string in user space. * * Returns the size of the string INCLUDING the terminating NUL. * On exception, returns 0. * * If there is a limit on the length of a valid string, you may wish to * consider using strnlen_user() instead. */ long strlen_user(const char __user *str) { unsigned long max_addr, src_addr; max_addr = user_addr_max(); src_addr = (unsigned long)str; if (likely(src_addr < max_addr)) { unsigned long max = max_addr - src_addr; return do_strnlen_user(str, ~0ul, max); } return 0; }
/** * strncpy_from_user: - Copy a NUL terminated string from userspace. * @dst: Destination address, in kernel space. This buffer must be at * least @count bytes long. * @src: Source address, in user space. * @count: Maximum number of bytes to copy, including the trailing NUL. * * Copies a NUL-terminated string from userspace to kernel space. * * On success, returns the length of the string (not including the trailing * NUL). * * If access to userspace fails, returns -EFAULT (some data may have been * copied). * * If @count is smaller than the length of the string, copies @count bytes * and returns @count. */ long strncpy_from_user(char *dst, const char __user *src, long count) { unsigned long max_addr, src_addr; if (unlikely(count <= 0)) return 0; max_addr = user_addr_max(); src_addr = (unsigned long)src; if (likely(src_addr < max_addr)) { unsigned long max = max_addr - src_addr; return do_strncpy_from_user(dst, src, count, max); } return -EFAULT; }
/** * strnlen_user: - Get the size of a user string INCLUDING final NUL. * @str: The string to measure. * @count: Maximum count (including NUL character) * * Context: User context only. This function may sleep. * * Get the size of a NUL-terminated string in user space. * * Returns the size of the string INCLUDING the terminating NUL. * If the string is too long, returns 'count+1'. * On exception (or invalid count), returns 0. */ long strnlen_user(const char __user *str, long count) { unsigned long max_addr, src_addr; if (unlikely(count <= 0)) return 0; max_addr = user_addr_max(); src_addr = (unsigned long)str; if (likely(src_addr < max_addr)) { unsigned long max = max_addr - src_addr; return do_strnlen_user(str, count, max); } return 0; }
static int lookup_bad_addr(const int type, const unsigned long addr, const size_t size) { /* Is this a valid memory access? * * Note we're using access_ok() here. This is only supposed to be * called when we're in task context. Occasionally lookup_bad_addr() * gets called when not in task context. If in_task() exists, only * call access_ok() when we're in task context (otherwise we'll get * a kernel warning). If we aren't in task context, we'll just do a * range check. */ #if !defined(in_task) if (size == 0 || ULONG_MAX - addr < size - 1 || !access_ok(type, (void *)addr, size)) return 1; #else if (size == 0 || ULONG_MAX - addr < size - 1 || (in_task() && !access_ok(type, (void *)addr, size)) || (!in_task() #if defined(user_addr_max) && ((user_addr_max() - size) < addr) #endif )) return 1; #endif #if ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPDEV) && \ ! STP_PRIVILEGE_CONTAINS (STP_PRIVILEGE, STP_PR_STAPSYS) /* Unprivileged users must not access memory while the context does not refer to their own process. */ if (! is_myproc ()) return 1; /* Unprivileged users must not access kernel space memory. */ if (addr + size > TASK_SIZE) return 1; #endif return 0; }