diff options
author | Clement Calmels <cboulte@gmail.com> | 2008-08-20 14:09:00 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-20 15:40:30 -0700 |
commit | 1804dc6e145f3f24a8c94deddfc0a986d380a27f (patch) | |
tree | 965ad5f3dfa7c6dc52bdfab7d838a82f78c8ad12 /fs | |
parent | 35fc908dc0e7ab0002ef18787886cc1340028020 (diff) | |
download | linux-3.10-1804dc6e145f3f24a8c94deddfc0a986d380a27f.tar.gz linux-3.10-1804dc6e145f3f24a8c94deddfc0a986d380a27f.tar.bz2 linux-3.10-1804dc6e145f3f24a8c94deddfc0a986d380a27f.zip |
/proc/self/maps doesn't display the real file offset
This addresses
http://bugzilla.kernel.org/show_bug.cgi?id=11318
In function show_map (file: fs/proc/task_mmu.c), if vma->vm_pgoff > 2^20
than (vma->vm_pgoff << PAGE_SIZE) is greater than 2^32 (with PAGE_SIZE
equal to 4096 (i.e. 2^12). The next seq_printf use an unsigned long for
the conversion of (vma->vm_pgoff << PAGE_SIZE), as a result the offset
value displayed in /proc/self/maps is truncated if the page offset is
greater than 2^20.
A test that shows this issue:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define PAGE_SIZE (getpagesize())
#if __i386__
# define U64_STR "%llx"
#elif __x86_64
# define U64_STR "%lx"
#else
# error "Architecture Unsupported"
#endif
int main(int argc, char *argv[])
{
int fd;
char *addr;
off64_t offset = 0x10000000;
char *filename = "/dev/zero";
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
offset *= 0x10;
printf("offset = " U64_STR "\n", offset);
addr = (char*)mmap64(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd,
offset);
if ((void*)addr == MAP_FAILED) {
perror("mmap64");
return 1;
}
{
FILE *fmaps;
char *line = NULL;
size_t len = 0;
ssize_t read;
size_t filename_len = strlen(filename);
fmaps = fopen("/proc/self/maps", "r");
if (!fmaps) {
perror("fopen");
return 1;
}
while ((read = getline(&line, &len, fmaps)) != -1) {
if ((read > filename_len + 1)
&& (strncmp(&line[read - filename_len - 1], filename, filename_len) == 0))
printf("%s", line);
}
if (line)
free(line);
fclose(fmaps);
}
close(fd);
return 0;
}
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Clement Calmels <cboulte@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/proc/nommu.c | 4 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 4 |
2 files changed, 4 insertions, 4 deletions
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 79ecd281d2c..3f87d263294 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -52,14 +52,14 @@ int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) } seq_printf(m, - "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", + "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", vma->vm_start, vma->vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', - vma->vm_pgoff << PAGE_SHIFT, + ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, MAJOR(dev), MINOR(dev), ino, &len); if (file) { diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7546a918f79..73d1891ee62 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -219,14 +219,14 @@ static int show_map(struct seq_file *m, void *v) ino = inode->i_ino; } - seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", vma->vm_start, vma->vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', - vma->vm_pgoff << PAGE_SHIFT, + ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, MAJOR(dev), MINOR(dev), ino, &len); /* |