STABLE14-osi-probe-check-readable-20070717

FIXES 63971

avoid potentially reading pges that don't exist


(cherry picked from commit 65c1b37f15e0fc7963aac9fa630613cf0d29df26)
This commit is contained in:
Jeffrey Hutzelman 2007-07-17 13:18:18 +00:00 committed by Derrick Brashear
parent cc10a541bd
commit f9c8440b21

View File

@ -59,6 +59,7 @@
#include "afsincludes.h"
#endif
#include <linux/version.h>
#include <linux/sched.h>
#ifdef CONFIG_H_EXISTS
#include <linux/config.h>
#endif
@ -153,6 +154,7 @@ MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
* 0x0010 - detail - check_harder
* 0x0020 - detail - check_harder/zapped
* 0x0040 - automatically ignore setgroups and afs_syscall
* 0x0080 - detail - check_table_readable
*/
static int probe_debug = 0x41;
#ifdef module_param
@ -298,6 +300,10 @@ typedef struct {
int debug_ignore_NR[4]; /* syscalls to ignore for debugging */
} probectl;
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
static int check_access(unsigned long, int);
static int check_table_readable(probectl *, PROBETYPE *);
#endif
/********** Probing Configuration: sys_call_table **********/
@ -947,6 +953,11 @@ static int check_table(probectl *P, PROBETYPE *ptr)
PROBETYPE *x;
int i, j;
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
i = check_table_readable(P, ptr);
if (i >= 0) return i;
#endif
for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
#ifdef OSI_PROBE_DEBUG
if (probe_debug & 0x0040) {
@ -1069,6 +1080,11 @@ static int check_harder(probectl *P, PROBETYPE *p)
unsigned long ip1;
int i, s;
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
i = check_table_readable(P, p);
if (i >= 0) return 0;
#endif
/* Check zapped syscalls */
for (i = 1; i < P->n_zapped_syscalls; i++) {
if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
@ -1356,7 +1372,7 @@ static void *do_find_syscall_table(probectl *P, char **method)
}
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
static int check_writable(unsigned long address)
static int check_access(unsigned long address, int mode)
{
pgd_t *pgd = pgd_offset_k(address);
#ifdef PUD_SIZE
@ -1381,10 +1397,34 @@ static int check_writable(unsigned long address)
pte = (pte_t *)pmd;
else
pte = pte_offset_kernel(pmd, address);
if (pte_none(*pte) || !pte_present(*pte) || !pte_write(*pte))
if (pte_none(*pte) || !pte_present(*pte))
return 0;
if (mode && !pte_write(*pte))
return 0;
return 1;
}
static int check_table_readable(probectl *P, PROBETYPE *ptr)
{
PROBETYPE *next_page;
int i = 0, delta;
while (i < _SS(NR_syscalls)) {
next_page = (PROBETYPE *)PAGE_ALIGN((unsigned long)(ptr+1));
delta = next_page - ptr;
if (!check_access((unsigned long)ptr, 0)) {
#ifdef OSI_PROBE_DEBUG
if (probe_debug & 0x0080)
printk("<7>osi_probe: %s 0x%016lx not readable; delta=0x%lx\n",
P->symbol, (unsigned long)ptr, delta);
#endif
return delta - 1;
}
ptr += delta;
i += delta;
}
return -1;
}
#endif
void *osi_find_syscall_table(int which)
@ -1412,7 +1452,7 @@ void *osi_find_syscall_table(int which)
}
printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
if (!check_writable((unsigned long)answer)) {
if (!check_access((unsigned long)answer, 1)) {
printk("Address 0x%lx is not writable.\n", (unsigned long)answer);
printk("System call hooks will not be installed; proceeding anyway\n");
return 0;