1 /* 2 * linux/fs/readdir.c 3 * 4 * Copyright (C) 1995 Linus Torvalds 5 */ 6 7 #include <linux/stddef.h> 8 #include <linux/kernel.h> 9 #include <linux/export.h> 10 #include <linux/time.h> 11 #include <linux/mm.h> 12 #include <linux/errno.h> 13 #include <linux/stat.h> 14 #include <linux/file.h> 15 #include <linux/fs.h> 16 #include <linux/fsnotify.h> 17 #include <linux/dirent.h> 18 #include <linux/security.h> 19 #include <linux/syscalls.h> 20 #include <linux/unistd.h> 21 #include <linux/compat.h> 22 23 #include <linux/uaccess.h> 24 25 int iterate_dir(struct file *file, struct dir_context *ctx) 26 { 27 struct inode *inode = file_inode(file); 28 bool shared = false; 29 int res = -ENOTDIR; 30 if (file->f_op->iterate_shared) 31 shared = true; 32 else if (!file->f_op->iterate) 33 goto out; 34 35 res = security_file_permission(file, MAY_READ); 36 if (res) 37 goto out; 38 39 if (shared) { 40 inode_lock_shared(inode); 41 } else { 42 res = down_write_killable(&inode->i_rwsem); 43 if (res) 44 goto out; 45 } 46 47 res = -ENOENT; 48 if (!IS_DEADDIR(inode)) { 49 ctx->pos = file->f_pos; 50 if (shared) 51 res = file->f_op->iterate_shared(file, ctx); 52 else 53 res = file->f_op->iterate(file, ctx); 54 file->f_pos = ctx->pos; 55 fsnotify_access(file); 56 file_accessed(file); 57 } 58 if (shared) 59 inode_unlock_shared(inode); 60 else 61 inode_unlock(inode); 62 out: 63 return res; 64 } 65 EXPORT_SYMBOL(iterate_dir); 66 67 /* 68 * Traditional linux readdir() handling.. 69 * 70 * "count=1" is a special case, meaning that the buffer is one 71 * dirent-structure in size and that the code can't handle more 72 * anyway. Thus the special "fillonedir()" function for that 73 * case (the low-level handlers don't need to care about this). 74 */ 75 76 #ifdef __ARCH_WANT_OLD_READDIR 77 78 struct old_linux_dirent { 79 unsigned long d_ino; 80 unsigned long d_offset; 81 unsigned short d_namlen; 82 char d_name[1]; 83 }; 84 85 struct readdir_callback { 86 struct dir_context ctx; 87 struct old_linux_dirent __user * dirent; 88 int result; 89 }; 90 91 static int fillonedir(struct dir_context *ctx, const char *name, int namlen, 92 loff_t offset, u64 ino, unsigned int d_type) 93 { 94 struct readdir_callback *buf = 95 container_of(ctx, struct readdir_callback, ctx); 96 struct old_linux_dirent __user * dirent; 97 unsigned long d_ino; 98 99 if (buf->result) 100 return -EINVAL; 101 d_ino = ino; 102 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 103 buf->result = -EOVERFLOW; 104 return -EOVERFLOW; 105 } 106 buf->result++; 107 dirent = buf->dirent; 108 if (!access_ok(VERIFY_WRITE, dirent, 109 (unsigned long)(dirent->d_name + namlen + 1) - 110 (unsigned long)dirent)) 111 goto efault; 112 if ( __put_user(d_ino, &dirent->d_ino) || 113 __put_user(offset, &dirent->d_offset) || 114 __put_user(namlen, &dirent->d_namlen) || 115 __copy_to_user(dirent->d_name, name, namlen) || 116 __put_user(0, dirent->d_name + namlen)) 117 goto efault; 118 return 0; 119 efault: 120 buf->result = -EFAULT; 121 return -EFAULT; 122 } 123 124 SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 125 struct old_linux_dirent __user *, dirent, unsigned int, count) 126 { 127 int error; 128 struct fd f = fdget_pos(fd); 129 struct readdir_callback buf = { 130 .ctx.actor = fillonedir, 131 .dirent = dirent 132 }; 133 134 if (!f.file) 135 return -EBADF; 136 137 error = iterate_dir(f.file, &buf.ctx); 138 if (buf.result) 139 error = buf.result; 140 141 fdput_pos(f); 142 return error; 143 } 144 145 #endif /* __ARCH_WANT_OLD_READDIR */ 146 147 /* 148 * New, all-improved, singing, dancing, iBCS2-compliant getdents() 149 * interface. 150 */ 151 struct linux_dirent { 152 unsigned long d_ino; 153 unsigned long d_off; 154 unsigned short d_reclen; 155 char d_name[1]; 156 }; 157 158 struct getdents_callback { 159 struct dir_context ctx; 160 struct linux_dirent __user * current_dir; 161 struct linux_dirent __user * previous; 162 int count; 163 int error; 164 }; 165 166 static int filldir(struct dir_context *ctx, const char *name, int namlen, 167 loff_t offset, u64 ino, unsigned int d_type) 168 { 169 struct linux_dirent __user * dirent; 170 struct getdents_callback *buf = 171 container_of(ctx, struct getdents_callback, ctx); 172 unsigned long d_ino; 173 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, 174 sizeof(long)); 175 176 buf->error = -EINVAL; /* only used if we fail.. */ 177 if (reclen > buf->count) 178 return -EINVAL; 179 d_ino = ino; 180 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 181 buf->error = -EOVERFLOW; 182 return -EOVERFLOW; 183 } 184 dirent = buf->previous; 185 if (dirent) { 186 if (signal_pending(current)) 187 return -EINTR; 188 if (__put_user(offset, &dirent->d_off)) 189 goto efault; 190 } 191 dirent = buf->current_dir; 192 if (__put_user(d_ino, &dirent->d_ino)) 193 goto efault; 194 if (__put_user(reclen, &dirent->d_reclen)) 195 goto efault; 196 if (copy_to_user(dirent->d_name, name, namlen)) 197 goto efault; 198 if (__put_user(0, dirent->d_name + namlen)) 199 goto efault; 200 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 201 goto efault; 202 buf->previous = dirent; 203 dirent = (void __user *)dirent + reclen; 204 buf->current_dir = dirent; 205 buf->count -= reclen; 206 return 0; 207 efault: 208 buf->error = -EFAULT; 209 return -EFAULT; 210 } 211 212 SYSCALL_DEFINE3(getdents, unsigned int, fd, 213 struct linux_dirent __user *, dirent, unsigned int, count) 214 { 215 struct fd f; 216 struct linux_dirent __user * lastdirent; 217 struct getdents_callback buf = { 218 .ctx.actor = filldir, 219 .count = count, 220 .current_dir = dirent 221 }; 222 int error; 223 224 if (!access_ok(VERIFY_WRITE, dirent, count)) 225 return -EFAULT; 226 227 f = fdget_pos(fd); 228 if (!f.file) 229 return -EBADF; 230 231 error = iterate_dir(f.file, &buf.ctx); 232 if (error >= 0) 233 error = buf.error; 234 lastdirent = buf.previous; 235 if (lastdirent) { 236 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 237 error = -EFAULT; 238 else 239 error = count - buf.count; 240 } 241 fdput_pos(f); 242 return error; 243 } 244 245 struct getdents_callback64 { 246 struct dir_context ctx; 247 struct linux_dirent64 __user * current_dir; 248 struct linux_dirent64 __user * previous; 249 int count; 250 int error; 251 }; 252 253 static int filldir64(struct dir_context *ctx, const char *name, int namlen, 254 loff_t offset, u64 ino, unsigned int d_type) 255 { 256 struct linux_dirent64 __user *dirent; 257 struct getdents_callback64 *buf = 258 container_of(ctx, struct getdents_callback64, ctx); 259 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, 260 sizeof(u64)); 261 262 buf->error = -EINVAL; /* only used if we fail.. */ 263 if (reclen > buf->count) 264 return -EINVAL; 265 dirent = buf->previous; 266 if (dirent) { 267 if (signal_pending(current)) 268 return -EINTR; 269 if (__put_user(offset, &dirent->d_off)) 270 goto efault; 271 } 272 dirent = buf->current_dir; 273 if (__put_user(ino, &dirent->d_ino)) 274 goto efault; 275 if (__put_user(0, &dirent->d_off)) 276 goto efault; 277 if (__put_user(reclen, &dirent->d_reclen)) 278 goto efault; 279 if (__put_user(d_type, &dirent->d_type)) 280 goto efault; 281 if (copy_to_user(dirent->d_name, name, namlen)) 282 goto efault; 283 if (__put_user(0, dirent->d_name + namlen)) 284 goto efault; 285 buf->previous = dirent; 286 dirent = (void __user *)dirent + reclen; 287 buf->current_dir = dirent; 288 buf->count -= reclen; 289 return 0; 290 efault: 291 buf->error = -EFAULT; 292 return -EFAULT; 293 } 294 295 SYSCALL_DEFINE3(getdents64, unsigned int, fd, 296 struct linux_dirent64 __user *, dirent, unsigned int, count) 297 { 298 struct fd f; 299 struct linux_dirent64 __user * lastdirent; 300 struct getdents_callback64 buf = { 301 .ctx.actor = filldir64, 302 .count = count, 303 .current_dir = dirent 304 }; 305 int error; 306 307 if (!access_ok(VERIFY_WRITE, dirent, count)) 308 return -EFAULT; 309 310 f = fdget_pos(fd); 311 if (!f.file) 312 return -EBADF; 313 314 error = iterate_dir(f.file, &buf.ctx); 315 if (error >= 0) 316 error = buf.error; 317 lastdirent = buf.previous; 318 if (lastdirent) { 319 typeof(lastdirent->d_off) d_off = buf.ctx.pos; 320 if (__put_user(d_off, &lastdirent->d_off)) 321 error = -EFAULT; 322 else 323 error = count - buf.count; 324 } 325 fdput_pos(f); 326 return error; 327 } 328 329 #ifdef CONFIG_COMPAT 330 struct compat_old_linux_dirent { 331 compat_ulong_t d_ino; 332 compat_ulong_t d_offset; 333 unsigned short d_namlen; 334 char d_name[1]; 335 }; 336 337 struct compat_readdir_callback { 338 struct dir_context ctx; 339 struct compat_old_linux_dirent __user *dirent; 340 int result; 341 }; 342 343 static int compat_fillonedir(struct dir_context *ctx, const char *name, 344 int namlen, loff_t offset, u64 ino, 345 unsigned int d_type) 346 { 347 struct compat_readdir_callback *buf = 348 container_of(ctx, struct compat_readdir_callback, ctx); 349 struct compat_old_linux_dirent __user *dirent; 350 compat_ulong_t d_ino; 351 352 if (buf->result) 353 return -EINVAL; 354 d_ino = ino; 355 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 356 buf->result = -EOVERFLOW; 357 return -EOVERFLOW; 358 } 359 buf->result++; 360 dirent = buf->dirent; 361 if (!access_ok(VERIFY_WRITE, dirent, 362 (unsigned long)(dirent->d_name + namlen + 1) - 363 (unsigned long)dirent)) 364 goto efault; 365 if ( __put_user(d_ino, &dirent->d_ino) || 366 __put_user(offset, &dirent->d_offset) || 367 __put_user(namlen, &dirent->d_namlen) || 368 __copy_to_user(dirent->d_name, name, namlen) || 369 __put_user(0, dirent->d_name + namlen)) 370 goto efault; 371 return 0; 372 efault: 373 buf->result = -EFAULT; 374 return -EFAULT; 375 } 376 377 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 378 struct compat_old_linux_dirent __user *, dirent, unsigned int, count) 379 { 380 int error; 381 struct fd f = fdget_pos(fd); 382 struct compat_readdir_callback buf = { 383 .ctx.actor = compat_fillonedir, 384 .dirent = dirent 385 }; 386 387 if (!f.file) 388 return -EBADF; 389 390 error = iterate_dir(f.file, &buf.ctx); 391 if (buf.result) 392 error = buf.result; 393 394 fdput_pos(f); 395 return error; 396 } 397 398 struct compat_linux_dirent { 399 compat_ulong_t d_ino; 400 compat_ulong_t d_off; 401 unsigned short d_reclen; 402 char d_name[1]; 403 }; 404 405 struct compat_getdents_callback { 406 struct dir_context ctx; 407 struct compat_linux_dirent __user *current_dir; 408 struct compat_linux_dirent __user *previous; 409 int count; 410 int error; 411 }; 412 413 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, 414 loff_t offset, u64 ino, unsigned int d_type) 415 { 416 struct compat_linux_dirent __user * dirent; 417 struct compat_getdents_callback *buf = 418 container_of(ctx, struct compat_getdents_callback, ctx); 419 compat_ulong_t d_ino; 420 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + 421 namlen + 2, sizeof(compat_long_t)); 422 423 buf->error = -EINVAL; /* only used if we fail.. */ 424 if (reclen > buf->count) 425 return -EINVAL; 426 d_ino = ino; 427 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 428 buf->error = -EOVERFLOW; 429 return -EOVERFLOW; 430 } 431 dirent = buf->previous; 432 if (dirent) { 433 if (signal_pending(current)) 434 return -EINTR; 435 if (__put_user(offset, &dirent->d_off)) 436 goto efault; 437 } 438 dirent = buf->current_dir; 439 if (__put_user(d_ino, &dirent->d_ino)) 440 goto efault; 441 if (__put_user(reclen, &dirent->d_reclen)) 442 goto efault; 443 if (copy_to_user(dirent->d_name, name, namlen)) 444 goto efault; 445 if (__put_user(0, dirent->d_name + namlen)) 446 goto efault; 447 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 448 goto efault; 449 buf->previous = dirent; 450 dirent = (void __user *)dirent + reclen; 451 buf->current_dir = dirent; 452 buf->count -= reclen; 453 return 0; 454 efault: 455 buf->error = -EFAULT; 456 return -EFAULT; 457 } 458 459 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, 460 struct compat_linux_dirent __user *, dirent, unsigned int, count) 461 { 462 struct fd f; 463 struct compat_linux_dirent __user * lastdirent; 464 struct compat_getdents_callback buf = { 465 .ctx.actor = compat_filldir, 466 .current_dir = dirent, 467 .count = count 468 }; 469 int error; 470 471 if (!access_ok(VERIFY_WRITE, dirent, count)) 472 return -EFAULT; 473 474 f = fdget_pos(fd); 475 if (!f.file) 476 return -EBADF; 477 478 error = iterate_dir(f.file, &buf.ctx); 479 if (error >= 0) 480 error = buf.error; 481 lastdirent = buf.previous; 482 if (lastdirent) { 483 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 484 error = -EFAULT; 485 else 486 error = count - buf.count; 487 } 488 fdput_pos(f); 489 return error; 490 } 491 #endif 492