/* * Utilities for the Linux Security Module for Chromium OS * (Since CONFIG_AUDIT is disabled for Chrome OS, we must repurpose * a bunch of the audit string handling logic here instead.) * * Copyright 2012 Google Inc. All Rights Reserved * * Author: * Kees Cook * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include "utils.h" /* Disallow double-quote and control characters other than space. */ static int contains_unprintable(const char *source, size_t len) { const unsigned char *p; for (p = source; p < (const unsigned char *)source + len; p++) { if (*p == '"' || *p < 0x20 || *p > 0x7e) return 1; } return 0; } static char *hex_printable(const char *source, size_t len) { size_t i; char *dest, *ptr; const char *hex = "0123456789ABCDEF"; /* Need to double the length of the string, plus a NULL. */ if (len > (INT_MAX - 1) / 2) return NULL; dest = kmalloc((len * 2) + 1, GFP_KERNEL); if (!dest) return NULL; for (ptr = dest, i = 0; i < len; i++) { *ptr++ = hex[(source[i] & 0xF0) >> 4]; *ptr++ = hex[source[i] & 0x0F]; } *ptr = '\0'; return dest; } static char *quoted_printable(const char *source, size_t len) { char *dest; /* Need to add 2 double quotes and a NULL. */ if (len > INT_MAX - 3) return NULL; dest = kmalloc(len + 3, GFP_KERNEL); if (!dest) return NULL; dest[0] = '"'; strcpy(dest + 1, source); dest[len + 1] = '"'; dest[len + 2] = '\0'; return dest; } /* Return a string that has been sanitized and is safe to log. It is either * in double-quotes, or is a series of hex digits. */ char *printable(char *source) { size_t len; if (!source) return NULL; len = strlen(source); if (contains_unprintable(source, len)) return hex_printable(source, len); else return quoted_printable(source, len); } /* Repurposed from fs/proc/base.c, with NULL-replacement for saner printing. * Allocates the buffer itself. */ char *printable_cmdline(struct task_struct *task) { char *buffer = NULL, *sanitized; int res, i; unsigned int len; struct mm_struct *mm; mm = get_task_mm(task); if (!mm) goto out; if (!mm->arg_end) goto out_mm; /* Shh! No looking before we're done */ buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buffer) goto out_mm; len = mm->arg_end - mm->arg_start; if (len > PAGE_SIZE) len = PAGE_SIZE; res = access_process_vm(task, mm->arg_start, buffer, len, 0); /* Space-fill NULLs. */ if (res > 1) for (i = 0; i < res - 2; ++i) if (buffer[i] == '\0') buffer[i] = ' '; /* If the NULL at the end of args has been overwritten, then * assume application is using setproctitle(3). */ if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { len = strnlen(buffer, res); if (len < res) { res = len; } else { len = mm->env_end - mm->env_start; if (len > PAGE_SIZE - res) len = PAGE_SIZE - res; res += access_process_vm(task, mm->env_start, buffer+res, len, 0); res = strnlen(buffer, res); } } /* Make sure result is printable. */ sanitized = printable(buffer); kfree(buffer); buffer = sanitized; out_mm: mmput(mm); out: return buffer; }