1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2011)
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
22   	 *
23   	 * ---------------------------------------
24   	 */
25   	
26   	/**
27   	 * @file  9p_interpreter.c
28   	 * @brief 9P interpretor
29   	 */
30   	
31   	#include "config.h"
32   	#include <stdio.h>
33   	#include <string.h>
34   	#include <pthread.h>
35   	
36   	#include "nfs_core.h"
37   	#include "9p.h"
38   	#include "fsal.h"
39   	#include "nfs_exports.h"
40   	#include "nfs_proto_functions.h"
41   	#include "nfs_dupreq.h"
42   	#include "nfs_file_handle.h"
43   	#include "server_stats.h"
44   	
45   	/* opcode to function array */
46   	const struct _9p_function_desc _9pfuncdesc[] = {
47   		[0] = {_9p_not_2000L, "no function"},	/* out of bounds */
48   		[_9P_TSTATFS] = {_9p_statfs, "_9P_TSTATFS"},
49   		[_9P_TLOPEN] = {_9p_lopen, "_9P_TLOPEN"},
50   		[_9P_TLCREATE] = {_9p_lcreate, "_9P_TLCREATE"},
51   		[_9P_TSYMLINK] = {_9p_symlink, "_9P_TSYMLINK"},
52   		[_9P_TMKNOD] = {_9p_mknod, "_9P_TMKNOD"},
53   		[_9P_TRENAME] = {_9p_rename, "_9P_TRENAME"},
54   		[_9P_TREADLINK] = {_9p_readlink, "_9P_TREADLINK"},
55   		[_9P_TGETATTR] = {_9p_getattr, "_9P_TGETATTR"},
56   		[_9P_TSETATTR] = {_9p_setattr, "_9P_TSETATTR"},
57   		[_9P_TXATTRWALK] = {_9p_xattrwalk, "_9P_TXATTRWALK"},
58   		[_9P_TXATTRCREATE] = {_9p_xattrcreate, "_9P_TXATTRCREATE"},
59   		[_9P_TREADDIR] = {_9p_readdir, "_9P_TREADDIR"},
60   		[_9P_TFSYNC] = {_9p_fsync, "_9P_TFSYNC"},
61   		[_9P_TLOCK] = {_9p_lock, "_9P_TLOCK"},
62   		[_9P_TGETLOCK] = {_9p_getlock, "_9P_TGETLOCK"},
63   		[_9P_TLINK] = {_9p_link, "_9P_TLINK"},
64   		[_9P_TMKDIR] = {_9p_mkdir, "_9P_TMKDIR"},
65   		[_9P_TRENAMEAT] = {_9p_renameat, "_9P_TRENAMEAT"},
66   		[_9P_TUNLINKAT] = {_9p_unlinkat, "_9P_TUNLINKAT"},
67   		[_9P_TVERSION] = {_9p_version, "_9P_TVERSION"},
68   		[_9P_TAUTH] = {_9p_auth, "_9P_TAUTH"},
69   		[_9P_TATTACH] = {_9p_attach, "_9P_TATTACH"},
70   		[_9P_TFLUSH] = {_9p_flush, "_9P_TFLUSH"},
71   		[_9P_TWALK] = {_9p_walk, "_9P_TWALK"},
72   		[_9P_TOPEN] = {_9p_not_2000L, "_9P_TOPEN"},
73   		[_9P_TCREATE] = {_9p_not_2000L, "_9P_TCREATE"},
74   		[_9P_TREAD] = {_9p_read, "_9P_TREAD"},
75   		[_9P_TWRITE] = {_9p_write, "_9P_TWRITE"},
76   		[_9P_TCLUNK] = {_9p_clunk, "_9P_TCLUNK"},
77   		[_9P_TREMOVE] = {_9p_remove, "_9P_TREMOVE"},
78   		[_9P_TSTAT] = {_9p_not_2000L, "_9P_TSTAT"},
79   		[_9P_TWSTAT] = {_9p_not_2000L, "_9P_TWSTAT"}
80   	};
81   	
82   	int _9p_not_2000L(struct _9p_request_data *req9p, u32 *plenout, char *preply)
83   	{
84   		char *msgdata = req9p->_9pmsg + _9P_HDR_SIZE;
85   		u8 msgtype = 0;
86   		u16 msgtag = 0;
87   		char *funcname = "inval";
88   	
89   		/* Get message's type */
90   		msgtype = *(u8 *)msgdata;
91   	
92   		/* TWSTAT is the last element in func_desc array, make sure
93   		 * we don't lookup past it */
94   		if (msgtype <= _9P_TWSTAT)
95   			funcname = _9pfuncdesc[msgtype].funcname;
96   	
97   		LogEvent(COMPONENT_9P,
98   			 "(%u|%s) is not a 9P2000.L message, returning ENOTSUP",
99   			 msgtype, funcname);
100  	
101  		_9p_rerror(req9p, &msgtag, ENOTSUP, plenout, preply);
102  	
103  		return -1;
104  	}				/* _9p_not_2000L */
105  	
106  	static ssize_t tcp_conn_send(struct _9p_conn *conn, const void *buf, size_t len,
107  				     int flags)
108  	{
109  		ssize_t ret;
110  	
111  		PTHREAD_MUTEX_lock(&conn->sock_lock);
112  		ret = send(conn->trans_data.sockfd, buf, len, flags);
113  		PTHREAD_MUTEX_unlock(&conn->sock_lock);
114  	
115  		if (ret < 0)
116  			server_stats_transport_done(conn->client,
117  						    0, 0, 0,
118  						    0, 0, 1);
119  		else
120  			server_stats_transport_done(conn->client,
121  						    0, 0, 0,
122  						    ret, 1, 0);
123  		return ret;
124  	}
125  	
126  	void _9p_tcp_process_request(struct _9p_request_data *req9p)
127  	{
128  		u32 outdatalen = 0;
129  		int rc = 0;
(1) Event stack_use_local_overflow: Local variable "replydata" uses 70000 bytes of stack space, which exceeds the maximum single use of 10000 bytes.
130  		char replydata[_9P_MSG_SIZE];
131  	
132  		rc = _9p_process_buffer(req9p, replydata, &outdatalen);
133  		if (rc != 1) {
134  			LogMajor(COMPONENT_9P,
135  				 "Could not process 9P buffer on socket #%lu",
136  				 req9p->pconn->trans_data.sockfd);
137  		} else {
138  			if (tcp_conn_send(req9p->pconn, replydata, outdatalen, 0) !=
139  			    outdatalen)
140  				LogMajor(COMPONENT_9P,
141  					 "Could not send 9P/TCP reply correctly on socket #%lu",
142  					 req9p->pconn->trans_data.sockfd);
143  		}
144  		_9p_DiscardFlushHook(req9p);
145  	}				/* _9p_process_request */
146  	
147  	int _9p_process_buffer(struct _9p_request_data *req9p, char *replydata,
148  			       u32 *poutlen)
149  	{
150  		char *msgdata;
151  		u32 msglen;
152  		u8 msgtype;
153  		int rc = 0;
154  	
155  		msgdata = req9p->_9pmsg;
156  	
157  		/* Get message's length */
158  		msglen = *(u32 *) msgdata;
159  		msgdata += _9P_HDR_SIZE;
160  	
161  		/* Get message's type */
162  		msgtype = *(u8 *) msgdata;
163  		msgdata += _9P_TYPE_SIZE;
164  	
165  		/* Check boundaries. 0 is no_function fallback */
166  		if (msgtype < _9P_TSTATFS || msgtype > _9P_TWSTAT
167  		    || _9pfuncdesc[msgtype].service_function == NULL)
168  			msgtype = 0;
169  	
170  		LogFullDebug(COMPONENT_9P, "9P msg: length=%u type (%u|%s)", msglen,
171  			     (u32) msgtype, _9pfuncdesc[msgtype].funcname);
172  	
173  		/* Temporarily set outlen to maximum message size. This value will be
174  		 * used inside the protocol functions for additional bound checking,
175  		 * and then replaced by the actual message size, (see _9p_checkbound())
176  		 */
177  		*poutlen = req9p->pconn->msize;
178  	
179  		/* Call the 9P service function */
180  		rc = _9pfuncdesc[msgtype].service_function(req9p, poutlen, replydata);
181  	
182  		/* Record 9P statistics */
183  		server_stats_9p_done(msgtype, req9p);
184  	
185  		_9p_release_opctx();
186  		op_ctx = NULL; /* poison the op context to disgard it */
187  		if (rc < 0)
188  			LogDebug(COMPONENT_9P, "%s: Error",
189  				 _9pfuncdesc[msgtype].funcname);
190  	
191  	/**
192  	 * @todo ops stats accounting goes here.
193  	 * service function return codes need to be reworked to return error code
194  	 * properly so that internal error code (currently -1) is distinguished
195  	 * from protocol op error, currently partially handled in rerror, and
196  	 * success return here so we can count errors and totals properly.
197  	 * I/O stats handled in read and write as in nfs.
198  	 */
199  		return rc;
200  	}
201