This source file includes following definitions.
- sysctl_init
- do_sysctl
- sys_sysctl
- in_egroup_p
- test_perm
- ctl_perm
- parse_table
- do_sysctl_strategy
- do_securelevel_strategy
- register_sysctl_table
- unregister_sysctl_table
- register_proc_table
- unregister_proc_table
- do_rw_proc
- proc_readsys
- proc_writesys
- proc_sys_permission
- proc_dostring
- proc_dointvec
- proc_dointvec_minmax
- proc_dostring
- proc_dointvec
- proc_dointvec_minmax
- sysctl_string
- sysctl_intvec
- do_string
- do_int
- do_struct
1
2
3
4
5
6
7
8
9 #include <linux/config.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/sysctl.h>
13 #include <linux/swapctl.h>
14 #include <linux/proc_fs.h>
15 #include <linux/malloc.h>
16 #include <linux/stat.h>
17 #include <linux/ctype.h>
18 #include <asm/bitops.h>
19 #include <asm/segment.h>
20
21 #include <linux/utsname.h>
22 #include <linux/swapctl.h>
23
24 static ctl_table root_table[];
25 static struct ctl_table_header root_table_header =
26 {root_table, DNODE_SINGLE(&root_table_header)};
27
28 static int parse_table(int *, int, void *, size_t *, void *, size_t,
29 ctl_table *, void **);
30
31 static ctl_table kern_table[];
32 static ctl_table vm_table[];
33
34
35
36 #ifdef CONFIG_PROC_FS
37
38 static int proc_readsys(struct inode * inode, struct file * file,
39 char * buf, int count);
40 static int proc_writesys(struct inode * inode, struct file * file,
41 const char * buf, int count);
42 static int proc_sys_permission(struct inode *, int);
43
44 struct file_operations proc_sys_file_operations =
45 {
46 NULL,
47 proc_readsys,
48 proc_writesys,
49 NULL,
50 NULL,
51 NULL,
52 NULL,
53 NULL,
54 NULL,
55 NULL
56 };
57
58 struct inode_operations proc_sys_inode_operations =
59 {
60 &proc_sys_file_operations,
61 NULL,
62 NULL,
63 NULL,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL,
70 NULL,
71 NULL,
72 NULL,
73 NULL,
74 NULL,
75 NULL,
76 proc_sys_permission
77 };
78
79 extern struct proc_dir_entry proc_sys_root;
80
81 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
82 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
83 #endif
84
85 extern int bdf_prm[], bdflush_min[], bdflush_max[];
86
87 static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
88 void *, size_t, void **);
89
90
91
92 static ctl_table root_table[] = {
93 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
94 {CTL_VM, "vm", NULL, 0, 0555, vm_table},
95 {0}
96 };
97
98 static ctl_table kern_table[] = {
99 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
100 0444, NULL, &proc_dostring, &sysctl_string},
101 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
102 0444, NULL, &proc_dostring, &sysctl_string},
103 {KERN_VERSION, "version", system_utsname.version, 64,
104 0444, NULL, &proc_dostring, &sysctl_string},
105 {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
106 0644, NULL, &proc_dostring, &sysctl_string},
107 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
108 0644, NULL, &proc_dostring, &sysctl_string},
109 {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
110 0444, NULL, &proc_dointvec},
111 {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
112 0644, NULL, &proc_dointvec},
113 {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
114 0444, NULL, &proc_dointvec},
115 {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
116 0644, NULL, &proc_dointvec},
117 {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
118 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
119 {0}
120 };
121
122 static ctl_table vm_table[] = {
123 {VM_SWAPCTL, "swapctl",
124 &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
125 {VM_KSWAPD, "kswapd",
126 &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
127 {VM_FREEPG, "freepages",
128 &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
129 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
130 &proc_dointvec_minmax, &sysctl_intvec, NULL,
131 &bdflush_min, &bdflush_max},
132 {0}
133 };
134
135 void sysctl_init(void)
136 {
137 #ifdef CONFIG_PROC_FS
138 register_proc_table(root_table, &proc_sys_root);
139 #endif
140 }
141
142
143 int do_sysctl (int *name, int nlen,
144 void *oldval, size_t *oldlenp,
145 void *newval, size_t newlen)
146 {
147 int error;
148 struct ctl_table_header *tmp;
149 void *context;
150
151 if (nlen == 0 || nlen >= CTL_MAXNAME)
152 return -ENOTDIR;
153
154 error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
155 if (error) return error;
156 if (oldval) {
157 if (!oldlenp)
158 return -EFAULT;
159 error = verify_area(VERIFY_WRITE,oldlenp,sizeof(size_t));
160 if (error) return error;
161 error = verify_area(VERIFY_WRITE,oldval,get_user(oldlenp));
162 if (error) return error;
163 }
164 if (newval) {
165 error = verify_area(VERIFY_READ,newval,newlen);
166 if (error) return error;
167 }
168 tmp = &root_table_header;
169 do {
170 context = 0;
171 error = parse_table(name, nlen, oldval, oldlenp,
172 newval, newlen, root_table, &context);
173 if (context)
174 kfree(context);
175 if (error != ENOTDIR)
176 return error;
177 tmp = tmp->DLIST_NEXT(ctl_entry);
178 } while (tmp != &root_table_header);
179 return -ENOTDIR;
180 }
181
182 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
183 {
184 struct __sysctl_args tmp;
185 int error;
186 error = verify_area(VERIFY_READ, args, sizeof(*args));
187 if (error)
188 return error;
189 memcpy_fromfs(&tmp, args, sizeof(tmp));
190 return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
191 tmp.newval, tmp.newlen);
192 }
193
194
195 static int in_egroup_p(gid_t grp)
196 {
197 int i;
198
199 if (grp == current->euid)
200 return 1;
201
202 for (i = 0; i < NGROUPS; i++) {
203 if (current->groups[i] == NOGROUP)
204 break;
205 if (current->groups[i] == grp)
206 return 1;
207 }
208 return 0;
209 }
210
211
212 static int test_perm(int mode, int op)
213 {
214 if (!current->euid)
215 mode >>= 6;
216 else if (in_egroup_p(0))
217 mode >>= 3;
218 if ((mode & op & 0007) == op)
219 return 0;
220 return -EACCES;
221 }
222 static inline int ctl_perm(ctl_table *table, int op)
223 {
224 return test_perm(table->mode, op);
225 }
226
227 static int parse_table(int *name, int nlen,
228 void *oldval, size_t *oldlenp,
229 void *newval, size_t newlen,
230 ctl_table *table, void **context)
231 {
232 int error;
233 repeat:
234 if (!nlen)
235 return -ENOTDIR;
236
237 for ( ; table->ctl_name; table++) {
238 if (get_user(name) == table->ctl_name ||
239 table->ctl_name == CTL_ANY) {
240 if (table->child) {
241 if (ctl_perm(table, 001))
242 return -EPERM;
243 if (table->strategy) {
244 error = table->strategy(
245 table, name, nlen,
246 oldval, oldlenp,
247 newval, newlen, context);
248 if (error)
249 return error;
250 }
251 name++;
252 nlen--;
253 table = table->child;
254 goto repeat;
255 }
256 error = do_sysctl_strategy(table, name, nlen,
257 oldval, oldlenp,
258 newval, newlen, context);
259 return error;
260 }
261 };
262 return -ENOTDIR;
263 }
264
265
266 int do_sysctl_strategy (ctl_table *table,
267 int *name, int nlen,
268 void *oldval, size_t *oldlenp,
269 void *newval, size_t newlen, void **context)
270 {
271 int op = 0, rc, len;
272
273 if (oldval)
274 op |= 004;
275 if (newval)
276 op |= 002;
277 if (ctl_perm(table, op))
278 return -EPERM;
279
280 if (table->strategy) {
281 rc = table->strategy(table, name, nlen, oldval, oldlenp,
282 newval, newlen, context);
283 if (rc < 0)
284 return rc;
285 if (rc > 0)
286 return 0;
287 }
288
289
290
291 if (table->data && table->maxlen) {
292 if (oldval && oldlenp && get_user(oldlenp)) {
293 len = get_user(oldlenp);
294 if (len > table->maxlen)
295 len = table->maxlen;
296 memcpy_tofs(oldval, table->data, len);
297 put_user(len, oldlenp);
298 }
299 if (newval && newlen) {
300 len = newlen;
301 if (len > table->maxlen)
302 len = table->maxlen;
303 memcpy_fromfs(table->data, newval, len);
304 }
305 }
306 return 0;
307 }
308
309
310
311
312
313
314 static int do_securelevel_strategy (ctl_table *table,
315 int *name, int nlen,
316 void *oldval, size_t *oldlenp,
317 void *newval, size_t newlen, void **context)
318 {
319 int level;
320
321 if (newval && newlen) {
322 if (newlen != sizeof (int))
323 return -EINVAL;
324 memcpy_fromfs (&level, newval, newlen);
325 if (level < securelevel && current->pid != 1)
326 return -EPERM;
327 }
328 return 0;
329 }
330
331 struct ctl_table_header *register_sysctl_table(ctl_table * table,
332 int insert_at_head)
333 {
334 struct ctl_table_header *tmp;
335 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
336 if (!tmp)
337 return 0;
338 *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
339 if (insert_at_head)
340 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
341 else
342 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
343 #ifdef CONFIG_PROC_FS
344 register_proc_table(table, &proc_sys_root);
345 #endif
346 return tmp;
347 }
348
349 void unregister_sysctl_table(struct ctl_table_header * table)
350 {
351 DLIST_DELETE(table, ctl_entry);
352 #ifdef CONFIG_PROC_FS
353 unregister_proc_table(table->ctl_table, &proc_sys_root);
354 #endif
355 }
356
357
358
359
360
361 #ifdef CONFIG_PROC_FS
362
363
364 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
365 {
366 struct proc_dir_entry *de;
367
368 for (; table->ctl_name; table++) {
369
370 if (!table->procname)
371 continue;
372
373 if (!table->proc_handler &&
374 !table->child)
375 continue;
376
377 de = kmalloc(sizeof(*de), GFP_KERNEL);
378 if (!de) continue;
379 de->namelen = strlen(table->procname);
380 de->name = table->procname;
381 de->mode = table->mode;
382 de->nlink = 1;
383 de->uid = 0;
384 de->gid = 0;
385 de->size = 0;
386 de->get_info = 0;
387 de->fill_inode = 0;
388 de->next = de->subdir = 0;
389 de->data = (void *) table;
390
391 if (table->proc_handler) {
392 de->ops = &proc_sys_inode_operations;
393 de->mode |= S_IFREG;
394 }
395
396 else {
397 de->ops = &proc_dir_inode_operations;
398 de->nlink++;
399 de->mode |= S_IFDIR;
400 }
401 table->de = de;
402 proc_register_dynamic(root, de);
403 if (de->mode & S_IFDIR )
404 register_proc_table(table->child, de);
405 }
406 }
407
408 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
409 {
410 struct proc_dir_entry *de;
411 for (; table->ctl_name; table++) {
412 if (!(de = table->de))
413 continue;
414 if (de->mode & S_IFDIR) {
415 if (!table->child) {
416 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
417 continue;
418 }
419 unregister_proc_table(table->child, de);
420 }
421 proc_unregister(root, de->low_ino);
422 kfree(de);
423 }
424 }
425
426
427 static int do_rw_proc(int write, struct inode * inode, struct file * file,
428 char * buf, int count)
429 {
430 int error, op;
431 struct proc_dir_entry *de;
432 struct ctl_table *table;
433 size_t res;
434
435 error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
436 if (error)
437 return error;
438
439 de = (struct proc_dir_entry*) inode->u.generic_ip;
440 if (!de || !de->data)
441 return -ENOTDIR;
442 table = (struct ctl_table *) de->data;
443 if (!table || !table->proc_handler)
444 return -ENOTDIR;
445 op = (write ? 002 : 004);
446 if (ctl_perm(table, op))
447 return -EPERM;
448
449 res = count;
450 error = (*table->proc_handler) (table, write, file, buf, &res);
451 if (error)
452 return error;
453 return res;
454 }
455
456 static int proc_readsys(struct inode * inode, struct file * file,
457 char * buf, int count)
458 {
459 return do_rw_proc(0, inode, file, buf, count);
460 }
461
462 static int proc_writesys(struct inode * inode, struct file * file,
463 const char * buf, int count)
464 {
465 return do_rw_proc(1, inode, file, (char *) buf, count);
466 }
467
468 static int proc_sys_permission(struct inode *inode, int op)
469 {
470 return test_perm(inode->i_mode, op);
471 }
472
473 int proc_dostring(ctl_table *table, int write, struct file *filp,
474 void *buffer, size_t *lenp)
475 {
476 int len;
477 char *p, c;
478
479 if (!table->data || !table->maxlen || !*lenp ||
480 (filp->f_pos && !write)) {
481 *lenp = 0;
482 return 0;
483 }
484
485 if (write) {
486 len = 0;
487 p = buffer;
488 while (len < *lenp &&
489 (c = get_user(p++)) != 0 && c != '\n')
490 len++;
491 if (len >= table->maxlen)
492 len = table->maxlen-1;
493 memcpy_fromfs(table->data, buffer, len);
494 ((char *) table->data)[len] = 0;
495 filp->f_pos += *lenp;
496 } else {
497 len = strlen(table->data) + 1;
498 if (len > table->maxlen)
499 len = table->maxlen;
500 if (len > *lenp)
501 len = *lenp;
502 if (len) {
503 memcpy_tofs(buffer, table->data, len-1);
504 put_user(0, ((char *) buffer) + len - 1);
505 }
506 if (len < *lenp) {
507 put_user('\n', ((char *) buffer) + len);
508 len++;
509 }
510 *lenp = len;
511 filp->f_pos += len;
512 }
513 return 0;
514 }
515
516 int proc_dointvec(ctl_table *table, int write, struct file *filp,
517 void *buffer, size_t *lenp)
518 {
519 int *i, vleft, first=1, len, left, neg, val;
520 #define TMPBUFLEN 20
521 char buf[TMPBUFLEN], *p;
522
523 if (!table->data || !table->maxlen || !*lenp ||
524 (filp->f_pos && !write)) {
525 *lenp = 0;
526 return 0;
527 }
528
529 i = (int *) table->data;
530 vleft = table->maxlen / sizeof(int);
531 left = *lenp;
532
533 for (; left && vleft--; i++, first=0) {
534 if (write) {
535 while (left && isspace(get_user((char *) buffer)))
536 left--, ((char *) buffer)++;
537 if (!left)
538 break;
539 neg = 0;
540 len = left;
541 if (len > TMPBUFLEN-1)
542 len = TMPBUFLEN-1;
543 memcpy_fromfs(buf, buffer, len);
544 buf[len] = 0;
545 p = buf;
546 if (*p == '-' && left > 1) {
547 neg = 1;
548 left--, p++;
549 }
550 if (*p < '0' || *p > '9')
551 break;
552 val = simple_strtoul(p, &p, 0);
553 len = p-buf;
554 if ((len < left) && *p && !isspace(*p))
555 break;
556 if (neg)
557 val = -val;
558 buffer += len;
559 left -= len;
560 *i = val;
561 } else {
562 p = buf;
563 if (!first)
564 *p++ = '\t';
565 sprintf(p, "%d", *i);
566 len = strlen(buf);
567 if (len > left)
568 len = left;
569 memcpy_tofs(buffer, buf, len);
570 left -= len;
571 buffer += len;
572 }
573 }
574
575 if (!write && !first && left) {
576 put_user('\n', (char *) buffer);
577 left--, buffer++;
578 }
579 if (write) {
580 p = (char *) buffer;
581 while (left && isspace(get_user(p++)))
582 left--;
583 }
584 if (write && first)
585 return -EINVAL;
586 *lenp -= left;
587 filp->f_pos += *lenp;
588 return 0;
589 }
590
591 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
592 void *buffer, size_t *lenp)
593 {
594 int *i, *min, *max, vleft, first=1, len, left, neg, val;
595 #define TMPBUFLEN 20
596 char buf[TMPBUFLEN], *p;
597
598 if (!table->data || !table->maxlen || !*lenp ||
599 (filp->f_pos && !write)) {
600 *lenp = 0;
601 return 0;
602 }
603
604 i = (int *) table->data;
605 min = (int *) table->extra1;
606 max = (int *) table->extra2;
607 vleft = table->maxlen / sizeof(int);
608 left = *lenp;
609
610 for (; left && vleft--; i++, first=0) {
611 if (write) {
612 while (left && isspace(get_user((char *) buffer)))
613 left--, ((char *) buffer)++;
614 if (!left)
615 break;
616 neg = 0;
617 len = left;
618 if (len > TMPBUFLEN-1)
619 len = TMPBUFLEN-1;
620 memcpy_fromfs(buf, buffer, len);
621 buf[len] = 0;
622 p = buf;
623 if (*p == '-' && left > 1) {
624 neg = 1;
625 left--, p++;
626 }
627 if (*p < '0' || *p > '9')
628 break;
629 val = simple_strtoul(p, &p, 0);
630 len = p-buf;
631 if ((len < left) && *p && !isspace(*p))
632 break;
633 if (neg)
634 val = -val;
635 buffer += len;
636 left -= len;
637
638 if (min && val < *min++)
639 continue;
640 if (max && val > *max++)
641 continue;
642 *i = val;
643 } else {
644 p = buf;
645 if (!first)
646 *p++ = '\t';
647 sprintf(p, "%d", *i);
648 len = strlen(buf);
649 if (len > left)
650 len = left;
651 memcpy_tofs(buffer, buf, len);
652 left -= len;
653 buffer += len;
654 }
655 }
656
657 if (!write && !first && left) {
658 put_user('\n', (char *) buffer);
659 left--, buffer++;
660 }
661 if (write) {
662 p = (char *) buffer;
663 while (left && isspace(get_user(p++)))
664 left--;
665 }
666 if (write && first)
667 return -EINVAL;
668 *lenp -= left;
669 filp->f_pos += *lenp;
670 return 0;
671 }
672
673 #else
674
675 int proc_dostring(ctl_table *table, int write, struct file *filp,
676 void *buffer, size_t *lenp)
677 {
678 return -ENOSYS;
679 }
680
681 int proc_dointvec(ctl_table *table, int write, struct file *filp,
682 void *buffer, size_t *lenp)
683 {
684 return -ENOSYS;
685 }
686
687 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
688 void *buffer, size_t *lenp)
689 {
690 return -ENOSYS;
691 }
692
693 #endif
694
695
696
697
698
699
700
701 int sysctl_string(ctl_table *table, int *name, int nlen,
702 void *oldval, size_t *oldlenp,
703 void *newval, size_t newlen, void **context)
704 {
705 int l, len;
706
707 if (!table->data || !table->maxlen)
708 return -ENOTDIR;
709
710 if (oldval && oldlenp && get_user(oldlenp)) {
711 len = get_user(oldlenp);
712 l = strlen(table->data);
713 if (len > l) len = l;
714 if (len >= table->maxlen)
715 len = table->maxlen;
716 memcpy_tofs(oldval, table->data, len);
717 put_user(0, ((char *) oldval) + len);
718 put_user(len, oldlenp);
719 }
720 if (newval && newlen) {
721 len = newlen;
722 if (len > table->maxlen)
723 len = table->maxlen;
724 memcpy_fromfs(table->data, newval, len);
725 if (len == table->maxlen)
726 len--;
727 ((char *) table->data)[len] = 0;
728 }
729 return 0;
730 }
731
732
733
734
735
736
737 int sysctl_intvec(ctl_table *table, int *name, int nlen,
738 void *oldval, size_t *oldlenp,
739 void *newval, size_t newlen, void **context)
740 {
741 int i, length, *vec, *min, *max;
742
743 if (newval && newlen) {
744 if (newlen % sizeof(int) != 0)
745 return -EINVAL;
746
747 if (!table->extra1 && !table->extra2)
748 return 0;
749
750 if (newlen > table->maxlen)
751 newlen = table->maxlen;
752 length = newlen / sizeof(int);
753
754 vec = (int *) newval;
755 min = (int *) table->extra1;
756 max = (int *) table->extra2;
757
758 for (i = 0; i < length; i++) {
759 int value = get_user(vec + i);
760 if (min && value < min[i])
761 return -EINVAL;
762 if (max && value > max[i])
763 return -EINVAL;
764 }
765 }
766 return 0;
767 }
768
769 int do_string (
770 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
771 int rdwr, char *data, size_t max)
772 {
773 int l = strlen(data) + 1;
774 if (newval && !rdwr)
775 return -EPERM;
776 if (newval && newlen >= max)
777 return -EINVAL;
778 if (oldval) {
779 if (l > get_user(oldlenp))
780 return -ENOMEM;
781 put_user(l, oldlenp);
782 memcpy_tofs(oldval, data, l);
783 }
784 if (newval) {
785 memcpy_fromfs(data, newval, newlen);
786 data[newlen] = 0;
787 }
788 return 0;
789 }
790
791 int do_int (
792 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
793 int rdwr, int *data)
794 {
795 if (newval && !rdwr)
796 return -EPERM;
797 if (newval && newlen != sizeof(int))
798 return -EINVAL;
799 if (oldval) {
800 if (get_user(oldlenp) < sizeof(int))
801 return -ENOMEM;
802 put_user(sizeof(int), oldlenp);
803 memcpy_tofs(oldval, data, sizeof(int));
804 }
805 if (newval)
806 memcpy_fromfs(data, newval, sizeof(int));
807 return 0;
808 }
809
810 int do_struct (
811 void *oldval, size_t *oldlenp, void *newval, size_t newlen,
812 int rdwr, void *data, size_t len)
813 {
814 if (newval && !rdwr)
815 return -EPERM;
816 if (newval && newlen != len)
817 return -EINVAL;
818 if (oldval) {
819 if (get_user(oldlenp) < len)
820 return -ENOMEM;
821 put_user(len, oldlenp);
822 memcpy_tofs(oldval, data, len);
823 }
824 if (newval)
825 memcpy_fromfs(data, newval, len);
826 return 0;
827 }
828