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