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