[Ocfs2-devel] [PATCH 2/2] Ocfs2: Implement new OCFS2_IOC_INFO ioctl for ocfs2.

Joel Becker Joel.Becker at oracle.com
Wed Dec 2 10:28:14 PST 2009


On Wed, Dec 02, 2009 at 10:29:28AM +0800, Tristan wrote:
> Joel Becker wrote:
> > struct ocfs2_info_request {
> > /*00*/	__u32 ir_magic;	/* Magic number */
> >   
> 
> Why we need a magic here, just to improve the security?

	Not for security - a malicious user can always fake the magic.
We need to solve security anyway.  The magic number is for convenience.
It catches stupid errors quickly.

> > ---------------------------------------------------------------------------
> > get_info(fd)
> > {
> > 	struct ocfs2_info_request_clustersize crq = {
> > 		.ir_magic = OCFS2_INFO_MAGIC,
> > 		.ir_code = OCFS2_INFO_REQUEST_CLUSTERSIZE,
> > 		.ir_size = sizeof(struct ocfs2Info_request_clustersize),
> > 	};
> > 	struct ocfs2_info_request_blocksize brq = {
> > 		.ir_magic = OCFS2_INFO_MAGIC,
> > 		.ir_code = OCFS2_INFO_REQUEST_BLOCKSIZE,
> > 		.ir_size = sizeof(struct ocfs2Info_request_blocksize),
> > 	};
> > 	uint64_t info_array[2] = {(unsigned long)&crq, (unsigned long)&brq};
> > 	struct ocfs2_info info = {
> > 		.info_requests = info_array,
> > 		.info_count = 2,
> > 	};
> > 	
> > 	rc = ioctl(fd, OCFS2_IOC_INFO, &info);
> > 	...
> > }
> > ---------------------------------------------------------------------------
> >
> > 	o2info can create convenience wrappers for setting the magic
> > number, code, and size, of course.  Note that we cast the request
> > pointers to unsigned longs so that the promotion from ulong to uint64_t
> > is handled by C.  This code works on 32bit and 64bit.
> >   
> 
> Just a confusion here, uint64_t should be 'unsigned long long' on 32bits 
> arch, and 'unsigned long' on 64bits arch, why we not use:
> 
> 
> uint64_t info_array[2] = {(unsigned long long)&crq, (unsigned long long)&brq};

	We're casting pointers.  A pointer is always the size of an
unsigned long.  By casting the pointers to unsigned long, we change them
from pointer types to integer types.  On 32bit this will be a 32bit
value, on 64bit a 64bit one.  That's all the casting does.  The C
compiler will notice we're assigning to uint64_t and promote any 32bit
value for us.

> > --------------------------------------------------------------------------
> > 	u64 req_addr;
> > 	struct ocfs2_info_request __user *reqp;
> >
> > 	for (i = 0; i < info->info_count; i++) {
> > 		ret = -EFAULT;
> > 		if (get_user(&req_addr,
> > 			     (unsigned long)((u64**)(info->info_requests) + i)))
> > 			break;
> > 		reqp = (struct ocfs2_info_request *)(unsigned long)req_addr;
> > 		ret = ocfs2_info_handle(file, reqp);
> > 		if (ret)
> > 			break;
> > 	}
> > --------------------------------------------------------------------------
> >   
> 
> How to avoid accessing an arbitrary mem address, such as, userspace 
> passing a wrong info_count(correct_info_count + 1), so the last entry 
> for pointer should be invalid, how to avoid to access that?

	get_user() will return non-zero if the address is not part of
the program's valid memory.  We then break and return -EFAULT, causing a
segfault.
	Note that we're checking two things.  In this function, we copy
the userspace pointer into reqp.  We haven't actually accessed the
memory at reqp, we've just copied the pointer from info->info_requests.
So here we've checked that info->info_requests+i is a valid memory
location.  In ocfs2_info_handle(), we then copy the actual request from
reqp.  There copy_from_user() is checking that reqp points to valid
memory before copying it.
	Btw, the above function should be checking that reqp is not NULL
;-)

Joel

-- 

"Vote early and vote often." 
        - Al Capone

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-devel mailing list