Print this page
Build provider 3rd arg from smb_request_t
hacking...
NEX-1643 dtrace provider for smbsrv
Also illumos 1841:
DTrace smb provider was mis-implemented, doesn't exist.
Add back handlers for read/write raw, so that
legacy dtrace consumers can find the probes.
Kill extra arg in smb_negotiate
Fix missing "done" probe with smb_notify
Add example consumer: smb-trace.d
fix soi_pid
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_read.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_read.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <smbsrv/smb_kproto.h>
27 27 #include <smbsrv/smb_fsops.h>
28 28
29 29 /*
30 30 * The maximum number of bytes to return from SMB Core
31 31 * SmbRead or SmbLockAndRead.
32 32 */
33 33 #define SMB_CORE_READ_MAX 4432
34 34
35 35 /*
36 36 * The limit in bytes for SmbReadX.
37 37 */
38 38 #define SMB_READX_MAX 0x10000
39 39
40 40 int smb_common_read(smb_request_t *, smb_rw_param_t *);
41 41
42 42 /*
43 43 * Read bytes from a file or named pipe (SMB Core).
44 44 *
45 45 * The requested count specifies the number of bytes desired. Offset
46 46 * is limited to 32 bits, so this client request is inappropriate for
47 47 * files with 64 bit offsets.
48 48 *
49 49 * On return, count is the number of bytes actually being returned, which
50 50 * may be less than the count requested only if a read specifies bytes
51 51 * beyond the current file size. In this case only the bytes that exist
52 52 * are returned. A read completely beyond the end of file results in a
53 53 * response of length zero. This is the only circumstance when a zero
54 54 * length response is generated. A count returned which is less than the
55 55 * count requested is the end of file indicator.
56 56 */
57 57 smb_sdrc_t
58 58 smb_pre_read(smb_request_t *sr)
59 59 {
60 60 smb_rw_param_t *param;
61 61 uint32_t off_low;
62 62 uint16_t count;
63 63 uint16_t remcnt;
64 64 int rc;
65 65
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
66 66 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
67 67 sr->arg.rw = param;
68 68
69 69 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
70 70 &count, &off_low, &remcnt);
71 71
72 72 param->rw_offset = (uint64_t)off_low;
73 73 param->rw_count = (uint32_t)count;
74 74 param->rw_mincnt = 0;
75 75
76 - DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
77 - smb_rw_param_t *, param);
76 + DTRACE_SMB_1(op__Read__start, smb_request_t *, sr); /* arg.rw */
78 77
79 78 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
80 79 }
81 80
82 81 void
83 82 smb_post_read(smb_request_t *sr)
84 83 {
85 - DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
86 - smb_rw_param_t *, sr->arg.rw);
84 + DTRACE_SMB_1(op__Read__done, smb_request_t *, sr); /* arg.rw */
87 85
88 86 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
89 87 }
90 88
91 89 smb_sdrc_t
92 90 smb_com_read(smb_request_t *sr)
93 91 {
94 92 smb_rw_param_t *param = sr->arg.rw;
95 93 uint16_t count;
96 94 int rc;
97 95
98 96 smbsr_lookup_file(sr);
99 97 if (sr->fid_ofile == NULL) {
100 98 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
101 99 return (SDRC_ERROR);
102 100 }
103 101
104 102 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
105 103
106 104 if (param->rw_count > SMB_CORE_READ_MAX)
107 105 param->rw_count = SMB_CORE_READ_MAX;
108 106
109 107 if ((rc = smb_common_read(sr, param)) != 0) {
110 108 smbsr_errno(sr, rc);
111 109 return (SDRC_ERROR);
112 110 }
113 111
114 112 count = (uint16_t)param->rw_count;
115 113 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
116 114 5, count, VAR_BCC, 0x01, count, &sr->raw_data);
117 115
118 116 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
119 117 }
120 118
121 119 /*
122 120 * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/
123 121 * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
124 122 * attempt to use it on non-disk shares.
125 123 *
126 124 * The requested count specifies the number of bytes desired. Offset
127 125 * specifies the offset in the file of the first byte to be locked then
128 126 * read. Note that offset is limited to 32 bits, so this client request
129 127 * is inappropriate for files with 64 bit offsets.
130 128 *
131 129 * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
132 130 * immediately an error should be returned to the client. If an error
133 131 * occurs on the lock, the bytes should not be read.
134 132 *
135 133 * On return, count is the number of bytes actually being returned, which
136 134 * may be less than the count requested only if a read specifies bytes
137 135 * beyond the current file size. In this case only the bytes that exist
138 136 * are returned. A read completely beyond the end of file results in a
139 137 * response of length zero. This is the only circumstance when a zero
140 138 * length response is generated. A count returned which is less than the
141 139 * count requested is the end of file indicator.
142 140 */
143 141 smb_sdrc_t
144 142 smb_pre_lock_and_read(smb_request_t *sr)
145 143 {
146 144 smb_rw_param_t *param;
147 145 uint32_t off_low;
148 146 uint16_t count;
149 147 uint16_t remcnt;
150 148 int rc;
151 149
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
152 150 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
153 151 sr->arg.rw = param;
154 152
155 153 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
156 154 &count, &off_low, &remcnt);
157 155
158 156 param->rw_offset = (uint64_t)off_low;
159 157 param->rw_count = (uint32_t)count;
160 158 param->rw_mincnt = 0;
161 159
162 - DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
163 - smb_rw_param_t *, param);
160 + DTRACE_SMB_1(op__LockAndRead__start, smb_request_t *, sr); /* arg.rw */
164 161
165 162 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
166 163 }
167 164
168 165 void
169 166 smb_post_lock_and_read(smb_request_t *sr)
170 167 {
171 - DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
172 - smb_rw_param_t *, sr->arg.rw);
168 + DTRACE_SMB_1(op__LockAndRead__done, smb_request_t *, sr); /* arg.rw */
173 169
174 170 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
175 171 }
176 172
177 173 smb_sdrc_t
178 174 smb_com_lock_and_read(smb_request_t *sr)
179 175 {
180 176 smb_rw_param_t *param = sr->arg.rw;
181 177 DWORD status;
182 178 uint32_t lk_pid;
183 179 uint16_t count;
184 180 int rc;
185 181
186 182 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
187 183 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
188 184 return (SDRC_ERROR);
189 185 }
190 186
191 187 smbsr_lookup_file(sr);
192 188 if (sr->fid_ofile == NULL) {
193 189 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
194 190 return (SDRC_ERROR);
195 191 }
196 192
197 193 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
198 194
199 195 /* Note: SMB1 locking uses 16-bit PIDs. */
200 196 lk_pid = sr->smb_pid & 0xFFFF;
201 197
202 198 status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
203 199 lk_pid, SMB_LOCK_TYPE_READWRITE, 0);
204 200
205 201 if (status != NT_STATUS_SUCCESS) {
206 202 smb_lock_range_error(sr, status);
207 203 return (SDRC_ERROR);
208 204 }
209 205
210 206 if (param->rw_count > SMB_CORE_READ_MAX)
211 207 param->rw_count = SMB_CORE_READ_MAX;
212 208
213 209 if ((rc = smb_common_read(sr, param)) != 0) {
214 210 smbsr_errno(sr, rc);
215 211 return (SDRC_ERROR);
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
216 212 }
217 213
218 214 count = (uint16_t)param->rw_count;
219 215 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
220 216 5, count, VAR_BCC, 0x1, count, &sr->raw_data);
221 217
222 218 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
223 219 }
224 220
225 221 /*
222 + * The SMB_COM_READ_RAW protocol was a negotiated option introduced in
223 + * SMB Core Plus to maximize performance when reading a large block
224 + * of data from a server. It's obsolete and no longer supported.
225 + *
226 + * We keep a handler for it so the dtrace provider can see if
227 + * the client tried to use this command.
228 + */
229 +smb_sdrc_t
230 +smb_pre_read_raw(smb_request_t *sr)
231 +{
232 + smb_rw_param_t *param;
233 + uint32_t off_low;
234 + uint32_t off_high;
235 + uint32_t timeout;
236 + uint16_t count;
237 + int rc;
238 +
239 + param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
240 + sr->arg.rw = param;
241 + if (sr->smb_wct == 8) {
242 + rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
243 + &off_low, &count, ¶m->rw_mincnt, &timeout);
244 + if (rc == 0) {
245 + param->rw_offset = (uint64_t)off_low;
246 + param->rw_count = (uint32_t)count;
247 + }
248 + } else {
249 + rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
250 + &off_low, &count, ¶m->rw_mincnt, &timeout, &off_high);
251 + if (rc == 0) {
252 + param->rw_offset = ((uint64_t)off_high << 32) | off_low;
253 + param->rw_count = (uint32_t)count;
254 + }
255 + }
256 + DTRACE_SMB_1(op__ReadRaw__start, smb_request_t *, sr); /* arg.rw */
257 + return (SDRC_SUCCESS);
258 +}
259 +
260 +void
261 +smb_post_read_raw(smb_request_t *sr)
262 +{
263 + DTRACE_SMB_1(op__ReadRaw__done, smb_request_t *, sr); /* arg.rw */
264 +
265 + kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
266 +}
267 +
268 +smb_sdrc_t
269 +smb_com_read_raw(smb_request_t *sr)
270 +{
271 + smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
272 + ERROR_NOT_SUPPORTED);
273 + return (SDRC_ERROR);
274 +}
275 +
276 +/*
226 277 * Read bytes from a file (SMB Core). This request was extended in
227 278 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
228 279 * 12 and including additional offset information.
229 280 *
230 281 * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
231 282 * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
232 283 * than the negotiated buffer size. If maxcnt_high is 0xFF, it must
233 284 * be ignored. Otherwise, maxcnt_high represents the upper 16 bits
234 285 * of rw_count.
235 286 */
236 287 smb_sdrc_t
237 288 smb_pre_read_andx(smb_request_t *sr)
238 289 {
239 290 smb_rw_param_t *param;
240 291 uint32_t off_low;
241 292 uint32_t off_high;
242 293 uint32_t maxcnt_high;
243 294 uint16_t maxcnt_low;
244 295 uint16_t mincnt;
245 296 uint16_t remcnt;
246 297 int rc;
247 298
248 299 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
249 300 sr->arg.rw = param;
250 301
251 302 if (sr->smb_wct == 12) {
252 303 rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", ¶m->rw_andx,
253 304 &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
254 305 &remcnt, &off_high);
255 306
256 307 param->rw_offset = ((uint64_t)off_high << 32) |
257 308 (uint64_t)off_low;
258 309
259 310 param->rw_count = (uint32_t)maxcnt_low;
260 311
261 312 if ((sr->session->capabilities & CAP_LARGE_READX) &&
262 313 (maxcnt_high < 0xFF))
263 314 param->rw_count |= maxcnt_high << 16;
264 315 } else {
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
265 316 rc = smbsr_decode_vwv(sr, "b3.wlwwlw", ¶m->rw_andx,
266 317 &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
267 318 &remcnt);
268 319
269 320 param->rw_offset = (uint64_t)off_low;
270 321 param->rw_count = (uint32_t)maxcnt_low;
271 322 }
272 323
273 324 param->rw_mincnt = 0;
274 325
275 - DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
276 - smb_rw_param_t *, param);
326 + DTRACE_SMB_1(op__ReadX__start, smb_request_t *, sr); /* arg.rw */
277 327
278 328 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
279 329 }
280 330
281 331 void
282 332 smb_post_read_andx(smb_request_t *sr)
283 333 {
284 - DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
285 - smb_rw_param_t *, sr->arg.rw);
334 + DTRACE_SMB_1(op__ReadX__done, smb_request_t *, sr); /* arg.rw */
286 335
287 336 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
288 337 }
289 338
290 339 smb_sdrc_t
291 340 smb_com_read_andx(smb_request_t *sr)
292 341 {
293 342 smb_rw_param_t *param = sr->arg.rw;
294 343 uint16_t datalen_high;
295 344 uint16_t datalen_low;
296 345 uint16_t data_offset;
297 346 uint16_t offset2;
298 347 int rc;
299 348
300 349 smbsr_lookup_file(sr);
301 350 if (sr->fid_ofile == NULL) {
302 351 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
303 352 return (SDRC_ERROR);
304 353 }
305 354
306 355 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
307 356
308 357 if (param->rw_count >= SMB_READX_MAX)
309 358 param->rw_count = 0;
310 359
311 360 if ((rc = smb_common_read(sr, param)) != 0) {
312 361 smbsr_errno(sr, rc);
313 362 return (SDRC_ERROR);
314 363 }
315 364
316 365 datalen_low = param->rw_count & 0xFFFF;
317 366 datalen_high = (param->rw_count >> 16) & 0xFF;
318 367
319 368 /*
320 369 * If this is a secondary command, the data offset
321 370 * includes the previous wct + sizeof(wct).
322 371 */
323 372 data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
324 373
325 374 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
326 375 data_offset += 60;
327 376 offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
328 377
329 378 rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
330 379 12, /* wct */
331 380 param->rw_andx, /* secondary andx command */
332 381 offset2, /* offset to next command */
333 382 0, /* set to 0 for named pipes */
334 383 datalen_low, /* data byte count */
335 384 data_offset, /* offset from start to data */
336 385 datalen_high, /* data byte count */
337 386 VAR_BCC, /* BCC marker */
338 387 0x00, /* padding */
339 388 &sr->raw_data);
340 389 } else {
341 390 data_offset += 59;
342 391 offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
343 392
344 393 rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
345 394 12, /* wct */
346 395 param->rw_andx, /* secondary andx command */
347 396 offset2, /* offset to next command */
348 397 -1, /* must be -1 for regular files */
349 398 datalen_low, /* data byte count */
350 399 data_offset, /* offset from start to data */
351 400 datalen_high, /* data byte count */
352 401 VAR_BCC, /* BCC marker */
353 402 &sr->raw_data);
354 403 }
355 404
356 405 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
357 406 }
358 407
359 408 /*
360 409 * Common function for reading files or IPC/MSRPC named pipes. All
361 410 * protocol read functions should lookup the fid before calling this
362 411 * function. We can't move the fid lookup here because lock-and-read
363 412 * requires the fid to do locking before attempting the read.
364 413 *
365 414 * Reading from a file should break oplocks on the file to LEVEL_II.
366 415 * A call to smb_oplock_break(SMB_OPLOCK_BREAK_TO_LEVEL_II) is not
367 416 * required as it is a no-op. If there's anything greater than a
368 417 * LEVEL_II oplock on the file, the oplock MUST be owned by the ofile
369 418 * on which the read is occuring and therefore would not be broken.
370 419 *
371 420 * Returns errno values.
372 421 */
373 422 int
374 423 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
375 424 {
376 425 smb_ofile_t *ofile = sr->fid_ofile;
377 426 smb_node_t *node;
378 427 smb_vdb_t *vdb = ¶m->rw_vdb;
379 428 struct mbuf *top;
380 429 int rc;
381 430
382 431 vdb->vdb_tag = 0;
383 432 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
384 433 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
385 434 vdb->vdb_uio.uio_resid = param->rw_count;
386 435 vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
387 436 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
388 437 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
389 438
390 439 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
391 440 case STYPE_DISKTREE:
392 441 node = ofile->f_node;
393 442
394 443 if (!smb_node_is_dir(node)) {
395 444 rc = smb_lock_range_access(sr, node, param->rw_offset,
396 445 param->rw_count, B_FALSE);
397 446 if (rc != NT_STATUS_SUCCESS) {
398 447 rc = ERANGE;
399 448 break;
400 449 }
401 450 }
402 451
403 452 if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
404 453 !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) {
405 454 /*
406 455 * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only
407 456 * reads.
408 457 *
409 458 * Reject request if the file has been opened
410 459 * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not
411 460 * set.
412 461 */
413 462 rc = EACCES;
414 463 break;
415 464 }
416 465
417 466 sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
418 467 top = smb_mbuf_allocate(&vdb->vdb_uio);
419 468
420 469 rc = smb_fsop_read(sr, sr->user_cr, node, ofile,
421 470 &vdb->vdb_uio);
422 471
423 472 sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
424 473 smb_mbuf_trim(top, sr->raw_data.max_bytes);
425 474 MBC_ATTACH_MBUF(&sr->raw_data, top);
426 475 break;
427 476
428 477 case STYPE_IPC:
429 478 sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
430 479 top = smb_mbuf_allocate(&vdb->vdb_uio);
431 480
432 481 rc = smb_opipe_read(sr, &vdb->vdb_uio);
433 482
434 483 sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
435 484 smb_mbuf_trim(top, sr->raw_data.max_bytes);
436 485 MBC_ATTACH_MBUF(&sr->raw_data, top);
437 486 break;
438 487
439 488 default:
440 489 rc = EACCES;
441 490 break;
442 491 }
443 492
444 493 param->rw_count -= vdb->vdb_uio.uio_resid;
445 494
446 495 if (rc != 0)
447 496 return (rc);
448 497
449 498 if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
450 499 /*
451 500 * mincnt is only used by read-raw and is typically
452 501 * zero. If mincnt is greater than zero and the
453 502 * number of bytes read is less than mincnt, tell
454 503 * the client that we read nothing.
455 504 */
456 505 param->rw_count = 0;
457 506 }
458 507
459 508 param->rw_offset += param->rw_count;
460 509 mutex_enter(&sr->fid_ofile->f_mutex);
461 510 ofile->f_seek_pos = param->rw_offset;
462 511 mutex_exit(&sr->fid_ofile->f_mutex);
463 512 return (rc);
464 513 }
↓ open down ↓ |
169 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX